Introduction

In 2017, the Tuveson Lab at Cold Spring Harbor Cancer Center published a paper written by Elyada et al that detailed the discovery of cancer-associated fibroblasts (CAFs) in mice. The subtypes were then validated in human samples affected with PDAC in a subsequent paper released in 2019. Here we will use SCISSORS to identify the CAF subtypes within the larger stroma population, fine-grained immune cell types within broadly-defined immune clusters, and ductal & PDAC subtypes within the ductal group. You can install SCISSORS from our GitHub repository.

Libraries

R

library(VAM)         # single cell GSEA
library(dplyr)       # tidy data 
library(Seurat)      # single cell infrastructure
library(ggplot2)     # pretty plots
library(SingleR)     # cell type assignment
library(decoderr)    # de novo deconvolution 
library(SCISSORS)    # our package
library(mixtools)    # Gaussian mixture model estimation
library(patchwork)   # align plots
library(latex2exp)   # LaTeX
library(paletteer)   # color palettes
library(CONICSmat)   # CNV estimation
library(reticulate)  # Python interface
library(kableExtra)  # pretty tables
library(wesanderson) # more color palettes

Python

import numpy as np
from openTSNE import TSNEEmbedding
from openTSNE import initialization
from openTSNE.affinity import Multiscale
from openTSNE.affinity import PerplexityBasedNN

Data

First we load in the \(\text{gene} \times \text{cell}\) counts matrix, then create a Seurat object to hold it in. Next, we add samplename, tissue type, and patient sex metadata taken from the publicly available dataset.

raw_counts <- Read10X(data.dir = "~/Desktop/Data/Elyada Raw/All Human/")
pdac <- CreateSeuratObject(raw_counts, 
                           project = "Elyada", 
                           min.cells = 3, 
                           min.features = 500)
pdac@meta.data$sample <- case_when(grepl("-1", rownames(pdac@meta.data)) ~ "SRR9274536", 
                                   grepl("-2", rownames(pdac@meta.data)) ~ "SRR9274537", 
                                   grepl("-3", rownames(pdac@meta.data)) ~ "SRR9274538", 
                                   grepl("-4", rownames(pdac@meta.data)) ~ "SRR9274539",
                                   grepl("-5", rownames(pdac@meta.data)) ~ "SRR9274540", 
                                   grepl("-6", rownames(pdac@meta.data)) ~ "SRR9274541", 
                                   grepl("-7", rownames(pdac@meta.data)) ~ "SRR9274542", 
                                   grepl("-8", rownames(pdac@meta.data)) ~ "SRR9274543", 
                                   grepl("-9", rownames(pdac@meta.data)) ~ "SRR9274544")
pdac@meta.data$condition <- case_when(grepl("-1", rownames(pdac@meta.data)) ~ "PDAC", 
                                      grepl("-2", rownames(pdac@meta.data)) ~ "PDAC", 
                                      grepl("-3", rownames(pdac@meta.data)) ~ "PDAC", 
                                      grepl("-4", rownames(pdac@meta.data)) ~ "PDAC", 
                                      grepl("-5", rownames(pdac@meta.data)) ~ "PDAC", 
                                      grepl("-6", rownames(pdac@meta.data)) ~ "AdjNorm", 
                                      grepl("-7", rownames(pdac@meta.data)) ~ "PDAC", 
                                      grepl("-8", rownames(pdac@meta.data)) ~ "AdjNorm", 
                                      grepl("-9", rownames(pdac@meta.data)) ~ "PDAC")
pdac@meta.data$sex <- case_when(grepl("-1", rownames(pdac@meta.data)) ~ "female", 
                                grepl("-2", rownames(pdac@meta.data)) ~ "male", 
                                grepl("-3", rownames(pdac@meta.data)) ~ "male", 
                                grepl("-4", rownames(pdac@meta.data)) ~ "male", 
                                grepl("-5", rownames(pdac@meta.data)) ~ "male", 
                                grepl("-6", rownames(pdac@meta.data)) ~ "female", 
                                grepl("-7", rownames(pdac@meta.data)) ~ "female", 
                                grepl("-8", rownames(pdac@meta.data)) ~ "male", 
                                grepl("-9", rownames(pdac@meta.data)) ~ "female")

Preprocessing

We run the typical single cell pre-processing steps on our cells - normalization, dimension reduction, and clustering.

pdac <- PrepareData(seurat.object = pdac, 
                    n.HVG = 4000, 
                    n.PC = 20, 
                    regress.mt = FALSE, 
                    regress.cc = FALSE, 
                    which.dim.reduc = "tsne", 
                    initial.resolution = 0.4, 
                    random.seed = 629)
## [1] "Running t-SNE on 20 principal components with perplexity = 30"
## [1] "Found 12 unique clusters"

Let’s check out the t-SNE embedding. It looks decent, but could definitely be improved. Globally, the clusters are arranged in a blob - which isn’t very informative - though the local structure seems to have been preserved fairly well. Visually, there are several clusters that contain subgroups - clusters 3, 4, 5, 6, & 9 look like good candidates for reclustering.

p0a <- DimPlot(pdac, reduction = "tsne", pt.size = 0.75) + 
       scale_color_paletteer_d("ggthemes::Classic_20") + 
       labs(x = "t-SNE 1", y = "t-SNE 2") + 
       theme_yehlab() + 
       theme(legend.text = element_text(size = 10)) + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p0a

We compute the distribution of the silhouette scores for each cluster.

sil_df <- ComputeSilhouetteScores(pdac, avg = FALSE)
p0b <- ggplot(sil_df, aes(x = Cluster, y = Score, fill = Cluster)) + 
       geom_violin(draw_quantiles = .5, color = "black", scale = "width") + 
       scale_fill_paletteer_d("ggthemes::Classic_20") + 
       labs(y = "Silhouette Score", fill = "Louvain\nClusters") + 
       theme_minimal() + 
       theme(panel.grid = element_blank(), 
             panel.border = element_rect(fill = NA, size = 1), 
             legend.position = "right", 
             legend.direction = "vertical", 
             axis.title.x = element_blank(), 
             legend.title = element_text(size = 22), 
             legend.text = element_text(size = 16), 
             axis.title.y = element_text(size = 22), 
             axis.text = element_text(size = 16), 
             axis.ticks = element_line(), 
             plot.subtitle = element_text(face = "italic", size = 10))

Looking at the silhouette score distribution for each cluster, we see that Cluster 10 seems to have the best fit, and Clusters 1, 2, & 9 seem to have pretty poor fits.

p0b

Lastly we’ll identify marker genes for each of the clusters.

pdac_markers <- FindAllMarkers(pdac, 
                               logfc.threshold = .5, 
                               test.use = "wilcox", 
                               only.pos = TRUE, 
                               random.seed = 629, 
                               verbose = FALSE) %>% 
                filter(p_val_adj < .05) %>% 
                group_by(cluster) %>% 
                arrange(desc(avg_log2FC)) %>% 
                slice_head(n = 5)
p0c <- DotPlot(pdac, features = unique(pdac_markers$gene), dot.scale = 10) + 
       scale_color_gradientn(colors = paletteer_d("wesanderson::Zissou1")) +
       labs(color = "Expression", size = "% Expressed", y = "Louvain Cluster") + 
       theme(axis.text.x = element_text(angle = 90, size = 10, vjust = 0.5), 
             legend.position = "right", legend.justification = "center", 
             panel.border = element_rect(fill = NA, size = 1, color = "black"), 
             axis.line = element_blank(), 
             legend.title = element_text(size = 14), 
             axis.title.x = element_blank(), 
             axis.title.y = element_text(size = 14), 
             axis.text.y = element_text(size = 18)) + 
       guides(color = guide_colorbar(title.position = "top", 
                                     barheight = unit(3, units = "cm"), title.hjust = 0.5), 
              size = guide_legend(title.position = "top", title.hjust = 0.5))
p0c

Optimize Dimension Reduction

I think the two-dimensional visualization of the cells could be improved. We’ll try using UMAP and the Fast Fourier Transform-accelerated Fit-SNE (as implemented in the openTSNE library) to improve the embedding.

UMAP

It seems like UMAP does a good job of clearly separating our clusters and preserving the global structure of the data. However, it’s difficult to see local structure within some of the clusters due to their density.

pdac <- RunUMAP(pdac, 
                reduction = "pca", 
                dims = 1:20, 
                umap.method = "uwot", 
                n.components = 2, 
                n.epochs = 750, 
                n.neighbors = 50, 
                metric = "cosine", 
                seed.use = 629, 
                verbose = FALSE)
p1 <- DimPlot(pdac, reduction = "umap", pt.size = 0.75) + 
      scale_color_paletteer_d("ggthemes::Classic_20") + 
      labs(x = "UMAP 1", y = "UMAP 2") + 
      theme_yehlab() +
      theme(legend.text = element_text(size = 10)) + 
      guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p1

Fit-SNE

For information on how to install the openTSNE implementation of Fit-SNE and how to run the algorithm, please visit the excellent GitHub repository of Pavlin Policar.

First we’ll run a simple, standard Fit-SNE embedding. It’s necessary to make the PCA embeddings accessible by Python.

pc_df <- Embeddings(pdac, reduction = "pca")
# import data
pc_df = np.array(r.pc_df)
# run Fit-SNE
affin = PerplexityBasedNN(pc_df, perplexity=30, metric='cosine', random_state=629)
init = initialization.pca(pc_df, random_state=629)
tsne1 = TSNEEmbedding(init, affin, negative_gradient_method='fft')
embed1 = tsne1.optimize(n_iter=350, exaggeration=12, momentum=0.6) 
embed2 = embed1.optimize(n_iter=750, momentum=0.8)

The embedding looks good, so we’ll use it going forwards.

embed <- as.matrix(py$embed2)
rownames(embed) <- colnames(pdac)
pdac@reductions$fitsne <- CreateDimReducObject(embeddings = embed, 
                                               key = "FitSNE_", 
                                               assay = "SCT", 
                                               global = TRUE)
p2 <- DimPlot(pdac, reduction = "fitsne", pt.size = 0.75) + 
      scale_color_paletteer_d("ggthemes::Classic_20") + 
      labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
      theme_yehlab() +
      theme(legend.text = element_text(size = 10)) + 
      guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p2

Due to the way Seurat accesses cell embeddings, we’ll need to replace our original t-SNE dimension reduction in our Seurat object with the new Fit-SNE version. We’ll keep the original Barnes-Hut t-SNE embedding under a separate name.

pdac@reductions$bh_tsne <- pdac@reductions$tsne
pdac@reductions$tsne <- pdac@reductions$fitsne

SingleR Cell Type Identification

Single Cell RNA-seq Reference Data

Here we use the SingleR package to identify broad cell types. The reference dataset we load is an sctransform-normalized version of the raw counts available in scRNAseq::BaronPancreasData(), which consists of normal pancreas cells that were sequenced and annotated by the researchers.

sc_ref <- readRDS("/Volumes/labs/Home/Jen Jen Yeh Lab/Jack/scRNAseq/Seurat/single_cell_ref_normalized.Rds")
sc_preds <- SingleR(test = data.frame(pdac@assays$SCT@data), 
                    ref = sc_ref, 
                    labels = sc_ref$label, 
                    method = "cluster", 
                    clusters = pdac$seurat_clusters, 
                    de.method = "wilcox")
pdac[["SingleR.labels.sc"]] <- sc_preds$labels[match(pdac[[]][["seurat_clusters"]], rownames(sc_preds))]
pdac$SingleR.labels.sc <- case_when(pdac$SingleR.labels.sc == "acinar" ~ "Acinar", 
                                    pdac$SingleR.labels.sc == "activated_stellate" ~ "Activated Stellate",
                                    pdac$SingleR.labels.sc == "ductal" ~ "Ductal", 
                                    pdac$SingleR.labels.sc == "macrophage" ~ "Macrophage",
                                    pdac$SingleR.labels.sc == "t_cell" ~ "T")

We can see that there’s a large immune population, as well as smaller ductal, fibroblast (denoted activated stellate in the reference dataset), and acinar groups. These broad cell types line up with what we expected to see given the authors’ original cell cluster annotations.

p3 <- DimPlot(pdac, reduction = "tsne", group.by = "SingleR.labels.sc", pt.size = 0.75) + 
      scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
      labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
      theme(plot.title = element_blank()) + 
      theme_yehlab() + 
      guides(color = guide_legend(nrow = 2, override.aes = list(size = 4)))
p3

Bulk Tissue RNA-seq Reference Data

This dataset is composed of labeled & log-normalized bulk RNA-seq samples from the Human Primary Cell Atlas.

bulk_ref <- HumanPrimaryCellAtlasData()
bulk_preds <- SingleR(test = data.frame(pdac@assays$SCT@data), 
                      ref = bulk_ref, 
                      labels = bulk_ref$label.main, 
                      method = "cluster", 
                      clusters = pdac$seurat_clusters, 
                      de.method = "wilcox")
pdac[["SingleR.labels.bulk"]] <- bulk_preds$labels[match(pdac[[]][["seurat_clusters"]], 
                                                         rownames(bulk_preds))]
pdac$SingleR.labels.bulk <- case_when(pdac$SingleR.labels.bulk == "B_cell" ~ "B", 
                                      pdac$SingleR.labels.bulk == "Epithelial_cells" ~ "Epithelial", 
                                      pdac$SingleR.labels.bulk == "B_cell-" ~ "B", 
                                      pdac$SingleR.labels.bulk == "T_cells" ~ "T",
                                      TRUE ~ pdac$SingleR.labels.bulk)

The bulk reference gives us somewhat more granular labels for the immune cells, and confirms the identities of the ductal / epithelial and stroma clusters.

p4 <- DimPlot(pdac, reduction = "tsne", group.by = "SingleR.labels.bulk", pt.size = 0.75) + 
      scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
      labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
      theme(plot.title = element_blank()) + 
      theme_yehlab() + 
      guides(color = guide_legend(nrow = 2, override.aes = list(size = 4)))
p4

One shouldn’t use SingleR as the final authority for cell types, but we were able to confirm the identities of the ductal and fibroblast clusters, which is important for this dataset as the cells we are most interested in are the cancer-associated fibroblasts (CAFs).

CONICSmat CNV Estimation

Next we’ll attempt to identify malignant cells using single-cell copy number variation estimation as implemented in the CONCISmat package. Details of the GMM methodology used can be found at the Diaz Lab’s GitHub repository. Note: this step is memory-intensive because 1) it requires the sparse counts matrix to be cast to a dense matrix and 2) a lot of Gaussian mixture models get estimated. If your machine doesn’t have a lot of RAM it might be best to skip this and manually annotate the malignant cells instead through the usage of canonical markers or the VAM single-cell GSEA methodology.

chrom_regions <- read.table("/Volumes/labs/Home/Jen Jen Yeh Lab/Jack/scRNAseq/chrom_arm_positions.txt", 
                            sep = "\t", 
                            row.names = 1, 
                            header = TRUE)
gene_pos <- getGenePositions(rownames(pdac))
cpm <- t(t(as.matrix(pdac@assays$SCT@counts)) / colSums(as.matrix(pdac@assays$SCT@counts))) * 10^5
cpm <- log2(cpm + 1)
norm_factor <- calcNormFactors(cpm)
cnv_est <- plotAll(mat = cpm, 
                   normFactor = norm_factor, 
                   regions = chrom_regions, 
                   gene_pos = gene_pos, 
                   fname = "Elyada")

Visualizing CNVs

After estimating CNVs, we cluster the cells into \(k = 3\) clusters, with the hope of finding one large cluster of normal cells and two smaller clusters composed of CAFs and PDAC cells.

bic_table <- read.table("./Elyada_BIC_LR.txt", 
                        sep = "\t", 
                        row.names = 1, 
                        header = TRUE, 
                        check.names = FALSE)
cand_regions <- rownames(bic_table[bic_table$`BIC difference` > 1000 & bic_table$`LRT adj. p-val` < .01, ])
hist1 <- plotHistogram(cnv_est[, cand_regions], 
                       cpm, 
                       clusters = 3, 
                       zscoreThreshold = 3, 
                       celltypes = pdac$SingleR.labels.bulk, 
                       patients = pdac$sample)

We add the normal vs. malignant cell labels in to our Seurat object’s metadata, then visualize the results. As expected, the malignant cells are located in the clusters identified by SingleR as ductal cells and fibroblasts. This indicates that CONICSmat did a solid job of estimating the CNVs - no easy feat with sparse, noisy single-cell data.

normal <- which(hist1 == 1)
malignant <- which(hist1 != 1)
pdac@meta.data$malig <- ifelse(rownames(pdac@meta.data) %in% names(normal), "Normal", "Malignant")
p5 <- DimPlot(pdac, reduction = "tsne", group.by = "malig", pt.size = 0.75) + 
      scale_color_manual(values = wes_palette("Zissou1", n = 5)[c(5, 2)]) + 
      labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
      theme(plot.title = element_blank()) + 
      theme_yehlab() + 
      guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p5

DECODER

Next, we use Dr. Xianlu Peng’s DECODER in order to deconvolve the dataset and assign weights to each cell using non-negative matrix factorization. We calculate basal & classical PDAC, normal & activated stroma, immune, and endocrine & exocrine pancreas compartment weights.

sample_wts_unscaled <- Decon_single_sample("TCGA_RNAseq_PAAD", pdac@assays$SCT@data, "geneSymbol")
sample_wts <- Norm_PDAC_weights(sample_wts_unscaled)
pdac <- AddMetaData(pdac, sample_wts$Immune, "immune")
pdac <- AddMetaData(pdac, sample_wts$bcRatio, "bc_ratio")
pdac <- AddMetaData(pdac, sample_wts$Exocrine, "exocrine")
pdac <- AddMetaData(pdac, sample_wts$Endocrine, "endocrine")
pdac <- AddMetaData(pdac, sample_wts_unscaled[, 9], "basal")
pdac <- AddMetaData(pdac, sample_wts_unscaled[, 5], "classical")
pdac <- AddMetaData(pdac, sample_wts$NormalStroma, "norm_stroma")
pdac <- AddMetaData(pdac, sample_wts$ActivatedStroma, "act_stroma")

Visualizing DECODER Weights

Basal PDAC

The basal weights are highest in a subcluster of the ductal group identified through SingleR. This is interesting as the authors did not find evidence of the basal subtype in their paper.

p6 <- FeaturePlot(pdac, reduction = "tsne", features = "basal", pt.size = 0.75) + 
      scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
      labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
      theme(plot.title = element_blank()) + 
      theme_yehlab() + 
      NoLegend()
p6

Classical PDAC

The classical weights are highest in another subcluster of the ductal cluster, and cells with high classical weights do not collocate with those that have high basal weights. The putative classical and basal PDAC cells also align closely with the cells identified through CONCISmat as malignant.

p7 <- FeaturePlot(pdac, reduction = "tsne", features = "classical", pt.size = 0.75) + 
      scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
      labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
      theme(plot.title = element_blank()) + 
      theme_yehlab() + 
      NoLegend()
p7

Exocrine Pancreas

The cluster identified through SingleR as acinar cells is the only cluster with high exocrine pancreas weights.

p8 <- FeaturePlot(pdac, reduction = "tsne", features = "exocrine", pt.size = 0.75) +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme(plot.title = element_blank()) + 
       theme_yehlab() + 
       NoLegend()
p8

Endocrine Pancreas

No cells have high endocrine pancreas weights.

p9 <- FeaturePlot(pdac, reduction = "tsne", features = "endocrine", pt.size = 0.75) +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme(plot.title = element_blank()) + 
       theme_yehlab() + 
       NoLegend()
p9

Immune

Once again, we confirm the largeness of the immune cell population in this dataset.

p10 <- FeaturePlot(pdac, reduction = "tsne", features = "immune", pt.size = 0.75) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme(plot.title = element_blank()) + 
       theme_yehlab() + 
       NoLegend()
p10

Normal Stroma

Cells with high normal stroma stroma weights are located in the cluster identified by SingleR as being stromal cells.

p11 <- FeaturePlot(pdac, reduction = "tsne", features = "norm_stroma", pt.size = 0.75) +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme(plot.title = element_blank()) + 
       theme_yehlab() + 
       NoLegend()
p11

Activated Stroma

Cells with high activated stroma weights are also located in the fibroblast cluster, and do not intersect with the cells that have high normal stroma scores. This indicates that SCISSORS will most likely perform well on the fibroblast cluster and be able to quickly tease out the cell subtypes.

p12 <- FeaturePlot(pdac, reduction = "tsne", features = "act_stroma", pt.size = 0.75) +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme(plot.title = element_blank()) + 
       theme_yehlab() + 
       NoLegend()
p12

SCISSORS

Now that we have rough labels from SingleR, CNVs from CONICSmat, and compartment weights from DECODER, we should have more than enough cell-level metadata to look for and annotate cell subtypes using SCISSORS.

Fibroblasts

The fibroblast marker genes provided by Elyada et al match the SingleR results defining cluster 6 as containing fibroblasts.

p13 <- FeaturePlot(pdac, reduction = "tsne", features = "COL1A1", pt.size = 0.75) +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "COL1A1") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p14 <- FeaturePlot(pdac, reduction = "tsne", features = "COL3A1", pt.size = 0.75) +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "COL3A1") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p15 <- FeaturePlot(pdac, reduction = "tsne", features = "LUM", pt.size = 0.75) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "LUM") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p16 <- FeaturePlot(pdac, reduction = "tsne", features = "DCN", pt.size = 0.75) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "DCN") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p13 | p14) / (p15 | p16)

Reclustering

Here we use ReclusterCells() to identify subclusters within cluster 6. We find five distinct subclusters.

fibro <- ReclusterCells(pdac,
                        which.clust = 6, 
                        n.HVG = 4000, 
                        n.PC = 20, 
                        resolution.vals = c(.03, .05, .1), 
                        k.vals = c(20, 30, 40), 
                        redo.embedding = TRUE)
fibro_pc <- Embeddings(fibro, "pca")
## [1] "Reclustering cells in cluster 6 using k = 20 & resolution = 0.03; S = 0.579"

We’ll again run Fit-SNE on the reclustered cells, for consistencies sake.

# import data
fibro_pc = r.fibro_pc
# run Fit-SNE
affin_fibro = PerplexityBasedNN(fibro_pc, perplexity=40, metric='cosine', random_state=629)
init = initialization.pca(fibro_pc, random_state=629)
tsne_f = TSNEEmbedding(init, affin_fibro, negative_gradient_method='fft')
embed_f1 = tsne_f.optimize(n_iter=250, exaggeration=5, momentum=0.4) 
embed_f2 = embed_f1.optimize(n_iter=750, exaggeration=1, momentum=0.8)

Pulling the results back into R and visualizing them shows clear separation between the subclusters. There’s some noise in subcluster 0, but other than that the reembedding looks solid.

embed_fibro <- as.matrix(py$embed_f2)
rownames(embed_fibro) <- colnames(fibro)
fibro@reductions$bh_tsne <- fibro@reductions$tsne
fibro@reductions$tsne<- CreateDimReducObject(embeddings = embed_fibro, 
                                             key = "FitSNE_", 
                                             assay = "SCT", 
                                             global = TRUE)
p17 <- DimPlot(fibro, reduction = "tsne", pt.size = 1.5) + 
       scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p17

Cell Type Identification

First we identify the endothelial and perivascular cells using PLVAP and RGS5 expression.

p18 <- FeaturePlot(fibro, reduction = "tsne", features = "PLVAP", pt.size = 1.5) +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "PLVAP") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p19 <- FeaturePlot(fibro, reduction = "tsne", features = "RGS5", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "RGS5") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p18 | p19) / p17

Next, we use the VAM method of single cell gene set enrichment analysis to determine which clusters are enriched for the iCAF and myCAF marker genes, as well as the general pan-CAF marker set. We use the marker genes identified by the authors.

icaf_genes <- c("IL6", "PDGFRA", "CXCL12", "CFD", "LMNA", 
                "AGTR1", "HAS1", "CXCL1", "CXCL2", "CCL2", "IL8")
mycaf_genes <- c("ACTA2", "TAGLN", "MMP11", "MYL9", 
                 "HOPX", "POSTN", "TPM1", "TPM2")
pan_caf_genes <- c("COL1A1", "FAP", "PDPN", "DCN", "VIM")
gene_sets <- list(icaf_genes, mycaf_genes, pan_caf_genes)
names(gene_sets) <- c("iCAF", "myCAF", "Pan-CAF")
for (i in seq(gene_sets)) {
  gene_sets[[i]] <- gene_sets[[i]][gene_sets[[i]] %in% rownames(fibro)]
}
fibro <- vamForSeurat(fibro, 
                      gene.set.collection = gene_sets, 
                      gamma = TRUE)
DefaultAssay(fibro) <- "VAMcdf"

iCAFs & myCAFs

We can easily define cluster 0 as the myCAF population, and cluster 2 as the slightly smaller iCAF population. Cluster 4 shows no enrichment whatsoever for either the iCAF or myCAF gene sets.

p20 <- FeaturePlot(fibro, reduction = "tsne", features = "iCAF", pt.size = 1.5) +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "iCAF") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p21 <- FeaturePlot(fibro, reduction = "tsne", features = "myCAF", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "myCAF") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p20 | p21) / p17

apCAFs

So we have a small cluster of 23 cells that does not appear to express any of the fibroblast, CAF, perivascular, or endothelial markers. After performing differential expression analysis, we find that the top 3 markers for cluster 4 are CLU, CD74, and CRYAB. Interestingly, CLU and CD74 were found to be differentially expressed in the apCAF population discovered in the KPC mouse models of CAFs in Elyada et al.

DefaultAssay(fibro) <- "SCT"
fibro_markers <- FindAllMarkers(fibro, 
                                assay = "SCT", 
                                logfc.threshold = 1.5, 
                                test.use = "wilcox", 
                                only.pos = TRUE, 
                                random.seed = 629, 
                                verbose = FALSE)
fibro_markers %>% 
  filter(cluster == 4) %>% 
  arrange(desc(avg_log2FC)) %>% 
  dplyr::select(cluster, gene, avg_log2FC, p_val_adj, pct.1, pct.2) %>% 
  slice_head(n = 5) %>% 
  kbl(booktabs = TRUE, digits = 4, row.names = FALSE) %>% 
  kable_minimal("hover", full_width = FALSE)
cluster gene avg_log2FC p_val_adj pct.1 pct.2
4 CLU 4.1036 0 1.000 0.359
4 CRYAB 4.1022 0 0.957 0.365
4 CD74 2.8741 0 0.957 0.317
4 HLA-DRA 2.5622 0 0.870 0.236
4 HLA-DRB1 2.3438 0 0.609 0.149

We re-run GSEA, again using the VAM package and the differentially expressed genes for the apCAF population as defined in Elyada et al (with the mouse gene names converted to HGNC symbols). We can see that the apCAF pathway is strongly enriched in cluster 4 as compared to the other CAF clusters.

apcaf_genes <- c("HLA-DQB1", "CD74", "SAA3P", "SLPI")
gene_sets <- list(icaf_genes, mycaf_genes, apcaf_genes, pan_caf_genes)
names(gene_sets) <- c("iCAF", "myCAF", "apCAF", "Pan-CAF")
for (i in seq(gene_sets)) {
  gene_sets[[i]] <- gene_sets[[i]][gene_sets[[i]] %in% rownames(fibro)]
}
fibro <- vamForSeurat(fibro, 
                      gene.set.collection = gene_sets, 
                      gamma = TRUE)
DefaultAssay(fibro) <- "VAMcdf"
p22 <- FeaturePlot(fibro, reduction = "tsne", features = "apCAF", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(title = "apCAF") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p22 / p17

Visualization

Finally, we add cell labels to our identified clusters.

fibro$label <- case_when(fibro$seurat_clusters == 0 ~ "myCAF", 
                         fibro$seurat_clusters == 1 ~ "Perivascular", 
                         fibro$seurat_clusters == 2 ~ "iCAF", 
                         fibro$seurat_clusters == 3 ~ "Endothelial", 
                         fibro$seurat_clusters == 4 ~ "apCAF")
Idents(fibro) <- "label"
p23a <- DimPlot(fibro, reduction = "tsne", pt.size = 1.5) + 
        scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        theme(plot.title = element_blank()) + 
        guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p23a

Here’s the marker genes for each cluster.

DefaultAssay(fibro) <- "SCT"
fibro_markers2 <- FindAllMarkers(fibro, 
                                 logfc.threshold = .5, 
                                 test.use = "wilcox", 
                                 only.pos = TRUE, 
                                 random.seed = 629, 
                                 verbose = FALSE) %>% 
                  filter(p_val_adj < .05) %>% 
                  group_by(cluster) %>% 
                  arrange(desc(avg_log2FC)) %>% 
                  slice_head(n = 5)
p23b <- DotPlot(fibro, features = fibro_markers2$gene, dot.scale = 10) + 
        scale_color_gradientn(colors = paletteer_d("wesanderson::Zissou1")) +
        labs(color = "Expression", size = "% Expressed") + 
        theme(axis.text.x = element_text(angle = 90, size = 12, vjust = 0.5), 
              legend.position = "right", legend.justification = "center", 
              panel.border = element_rect(fill = NA, size = 1, color = "black"), 
              axis.line = element_blank(), 
              legend.title = element_text(size = 16), 
              axis.title.y = element_blank(), 
              axis.title.x = element_blank(), 
              axis.text.y = element_text(size = 18)) + 
        guides(color = guide_colorbar(title.position = "top", 
                                      barheight = unit(3, units = "cm"), title.hjust = 0.5), 
               size = guide_legend(title.position = "top", title.hjust = 0.5))
p23b

T Cells

Going back to the main Seurat object, we should have a large population of T and NK cells that warrants further investigation. Using CD3D expression we can easily identify clusters 0, 3, and 7 as the mixed T & NK cells. We already see some good separation, so reclustering the cells should have good results.

p24 <- FeaturePlot(pdac, reduction = "tsne", features = "CD3D", pt.size = 0.75) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p24 / p2

Tumor

nkt_tumor <- subset(pdac, subset = seurat_clusters %in% c(0, 3, 8) & condition == "PDAC")

Reclustering

Here we run ReclusterCells(), while treating the NK & T cell clusters as one large group. This will hopefully allow use to elucidate T cell subtypes. We use fewer PCs for these cells since the differences between immune cells are subtle, and adding more PCs will most likely only contribute noise to our analyses.

nkt_tumor <- ReclusterCells(nkt_tumor, 
                            which.clust = list(0, 3, 8), 
                            merge.clusters = TRUE, 
                            n.HVG = 4000, 
                            n.PC = 15, 
                            k.vals = c(30, 40, 50, 60), 
                            resolution.vals = c(.1, .2, .3), 
                            redo.embedding = TRUE, 
                            random.seed = 629)
nkt_tumor_pc <- Embeddings(nkt_tumor, "pca")
## [1] "Reclustering cells in clusters 0, 3, 8 using k = 30 & resolution = 0.3; S = 0.455"

Once again we’ll run Fit-SNE on the reclustered cells.

# import data
nkt_tumor_pc = r.nkt_tumor_pc
# run Fit-SNE
affin_nkt_tumor = PerplexityBasedNN(nkt_tumor_pc, perplexity=100, metric='cosine', random_state=629)
init = initialization.pca(nkt_tumor_pc, random_state=629)
tsne_nkt_tumor = TSNEEmbedding(init, affin_nkt_tumor, negative_gradient_method='fft')
embed_nkt_tumor1 = tsne_nkt_tumor.optimize(n_iter=250, exaggeration=4, momentum=0.6) 
embed_nkt_tumor2 = embed_nkt_tumor1.optimize(n_iter=750, exaggeration=1, momentum=0.8)
affin_nkt_tumor.set_perplexity(50)
embed_nkt_tumor3 = embed_nkt_tumor2.optimize(n_iter=500, exaggeration=1, momentum=0.6)

The reembedding isn’t perfect, which we somewhat expected as immune cells are difficult to tell apart based on the transcriptome alone.

embed_nkt_tumor <- as.matrix(py$embed_nkt_tumor3)
rownames(embed_nkt_tumor) <- colnames(nkt_tumor)
nkt_tumor@reductions$bh_tsne <- nkt_tumor@reductions$tsne
nkt_tumor@reductions$tsne<- CreateDimReducObject(embeddings = embed_nkt_tumor, 
                                                 key = "FitSNE_", 
                                                 assay = "SCT", 
                                                 global = TRUE)
p25 <- DimPlot(nkt_tumor, reduction = "tsne", pt.size = 1.5) + 
       scale_color_manual(values = paletteer_d("ggsci::category20_d3")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p25

Cell Type Identification

CD4+ T

Clusters 0 and 1 contain our CD4+ T cells, which we characterize using IL7R as we did in the PBMC3k vignette. It’s somewhat outside of our scope here to determine which subtype each cluster belongs to, so we’ll simply assign both clusters the same label and move on.

p26 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "IL7R", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p27 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "CD69", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p26 | p27) / p25

T-regs

Cluster 3 contains the regulatory T cells.

p28 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "IL2RA", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p29 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "FOXP3", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p28 | p29) / p25

Proliferating T-regs

We can find the proliferating T-regs in cluster 7.

p30 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "TOP2A", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p30 / p25

Mast

Mast cells can be identified using TPSAB1 expression in cluster 6.

p31 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "TPSAB1", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p31 / p25

NK

NKG7 and PRF1 show us the NK cells in cluster 5.

p32 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "NKG7", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p33 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "PRF1", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p32 | p33) / p25

CD8+ T

We use CD8A and CD2 to reveal the CD8+ T cells within clusters 2 and 4.

p34 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "CD8A", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p35 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "CD2", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p34 | p35) / p25

Intermediate Monocyte

Lastly, we have cluster 8, which doesn’t highly express our pan-T/NK cell markers CD3D and CD2. It could be a myeloid cell cluster that was mistakenly grouped with the T/NK cells. We’ll start with a Wilcoxon test to determine its differentially expressed genes. Interestingly, several intermediate monocyte markers - LYZ, HLA-DRA, CD74, and HLA-DPB1 - are differentially expressed in cluster 8.

clust8_markers <- FindAllMarkers(nkt_tumor, 
                                 test.use = "wilcox",
                                 min.diff.pct = .2,
                                 logfc.threshold = .5, 
                                 verbose = FALSE, 
                                 random.seed = 629) %>% 
                  filter(cluster == 8, p_val_adj < .05) %>% 
                  arrange(desc(1 - p_val_adj))
clust8_markers %>% 
  filter(gene %in% c("LYZ", "HLA-DRA", "CD74", "HLA-DPB1")) %>% 
  dplyr::select(cluster, gene, avg_log2FC, p_val_adj, pct.1, pct.2) %>% 
  kbl(booktabs = TRUE, digits = 4, row.names = FALSE) %>% 
  kable_minimal("hover", full_width = FALSE)
cluster gene avg_log2FC p_val_adj pct.1 pct.2
8 HLA-DRA 3.1725 0 0.974 0.410
8 HLA-DPB1 2.2895 0 0.895 0.387
8 CD74 2.7595 0 0.974 0.723
8 LYZ 1.9255 0 0.526 0.107

We’ll plot some of those markers below.

p36 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "LYZ", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p37 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "HLA-DRA", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p38 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "CD74", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p39 <- FeaturePlot(nkt_tumor, reduction = "tsne", features = "HLA-DPB1", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
((p36 | p37) / (p38 | p39)) / p25

Visualization

We add labels to our T cell Seurat object and visualize the results.

nkt_tumor$label <- case_when(nkt_tumor$seurat_clusters == 0 ~ "CD4+ T", 
                             nkt_tumor$seurat_clusters == 1 ~ "CD4+ T", 
                             nkt_tumor$seurat_clusters == 2 ~ "CD8+ T", 
                             nkt_tumor$seurat_clusters == 3 ~ "T-reg", 
                             nkt_tumor$seurat_clusters == 4 ~ "CD8+ T", 
                             nkt_tumor$seurat_clusters == 5 ~ "NK", 
                             nkt_tumor$seurat_clusters == 6 ~ "Mast", 
                             nkt_tumor$seurat_clusters == 7 ~ "Proliferating T-reg", 
                             nkt_tumor$seurat_clusters == 8 ~ "Intermediate Monocyte")
Idents(nkt_tumor) <- "label"
p40a <- DimPlot(nkt_tumor, reduction = "tsne", pt.size = 1.5) + 
        scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        theme(plot.title = element_blank()) + 
        guides(color = guide_legend(nrow = 2, override.aes = list(size = 4)))
p40a

Here’s the marker genes.

nkt_tumor_markers2 <- FindAllMarkers(nkt_tumor, 
                                     logfc.threshold = .5, 
                                     test.use = "wilcox", 
                                     only.pos = TRUE, 
                                     random.seed = 629, 
                                     verbose = FALSE) %>% 
                      filter(p_val_adj < .05) %>% 
                      group_by(cluster) %>% 
                      arrange(desc(avg_log2FC)) %>% 
                      slice_head(n = 5)
p40b <- DotPlot(nkt_tumor, features = unique(nkt_tumor_markers2$gene), dot.scale = 10) + 
        scale_color_gradientn(colors = paletteer_d("wesanderson::Zissou1")) +
        labs(color = "Expression", size = "% Expressed") + 
        theme(axis.text.x = element_text(angle = 90, size = 9, vjust = 0.5), 
              legend.position = "right", legend.justification = "center", 
              panel.border = element_rect(fill = NA, size = 1, color = "black"), 
              axis.line = element_blank(), 
              legend.title = element_text(size = 14), 
              axis.title.y = element_blank(), 
              axis.title.x = element_blank(), 
              axis.text.y = element_text(size = 14)) + 
        guides(color = guide_colorbar(title.position = "top", 
                                      barheight = unit(3, units = "cm"), title.hjust = 0.5), 
               size = guide_legend(title.position = "top", title.hjust = 0.5))
p40b

Adjacent Normal

nkt_norm <- subset(pdac, subset = seurat_clusters %in% c(0, 3, 8) & condition == "AdjNorm")

Reclustering

nkt_norm <- ReclusterCells(nkt_norm, 
                           which.clust = list(0, 3, 8), 
                           merge.clusters = TRUE, 
                           n.HVG = 4000, 
                           n.PC = 10, 
                           k.vals = c(15, 20, 25), 
                           resolution.vals = c(.2, .3, .4), 
                           nn.metric = "euclidean", 
                           redo.embedding = TRUE, 
                           random.seed = 629)
nkt_norm_pc <- Embeddings(nkt_norm, "pca")
## [1] "Reclustering cells in clusters 0, 3, 8 using k = 15 & resolution = 0.3; S = 0.438"

As with the other reclusterings, we’ll run Fit-SNE in order to (hopefully) obtain a better low-dimensional embedding of our cells.

# import data
nkt_norm_pc = r.nkt_norm_pc
# run Fit-SNE
affin_nkt_norm = PerplexityBasedNN(nkt_norm_pc, perplexity=30, metric='cosine', random_state=629)
init = initialization.pca(nkt_norm_pc, random_state=629)
tsne_nkt_norm = TSNEEmbedding(init, affin_nkt_norm, negative_gradient_method='fft')
embed_nkt_norm1 = tsne_nkt_norm.optimize(n_iter=250, exaggeration=12, momentum=0.6) 
embed_nkt_norm2 = embed_nkt_norm1.optimize(n_iter=750, exaggeration=1, momentum=0.8)
embed_nkt_norm <- as.matrix(py$embed_nkt_norm2)
rownames(embed_nkt_norm) <- colnames(nkt_norm)
nkt_norm@reductions$bh_tsne <- nkt_norm@reductions$tsne
nkt_norm@reductions$tsne<- CreateDimReducObject(embeddings = embed_nkt_norm, 
                                                key = "FitSNE_", 
                                                assay = "SCT", 
                                                global = TRUE)
p41 <- DimPlot(nkt_norm, reduction = "tsne", pt.size = 1.5) + 
       scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p41

Cell Type Identification

First we’ll use a Wilcoxon test to determine which genes characterize each cluster.

nkt_norm_markers <- FindAllMarkers(nkt_norm, 
                                   logfc.threshold = .5, 
                                   min.diff.pct = .2, 
                                   verbose = FALSE, 
                                   only.pos = TRUE, 
                                   random.seed = 629) %>% 
                    filter(p_val_adj < .05)
nkt_norm_markers  %>% 
  dplyr::select(cluster, gene, avg_log2FC, p_val_adj, pct.1, pct.2) %>% 
  group_by(cluster) %>% 
  top_n(n = 3, wt = avg_log2FC) %>% 
  kbl(booktabs = TRUE, digits = 4) %>% 
  kable_minimal("hover", full_width = FALSE)
cluster gene avg_log2FC p_val_adj pct.1 pct.2
0 KLRB1 1.7367 0 0.843 0.316
0 IL7R 0.8630 0 0.897 0.612
1 GZMK 1.5317 0 0.925 0.350
1 CST7 0.9069 0 0.846 0.452
1 CCL4 1.0830 0 0.817 0.377
3 KLRC1 0.8868 0 0.429 0.050
3 GNLY 1.2618 0 0.521 0.122
3 HOPX 0.6239 0 0.663 0.297
4 GZMB 2.3387 0 0.730 0.090
4 NKG7 2.2958 0 0.873 0.515
4 GNLY 2.5414 0 0.611 0.149
5 TNFRSF4 1.7814 0 0.691 0.043
5 TNFRSF18 1.6798 0 0.660 0.047
5 LTB 1.7286 0 0.915 0.472
6 SELL 1.1920 0 0.761 0.080
6 CCR7 1.0374 0 0.705 0.107
6 EIF3E 0.7694 0 0.830 0.520
7 STMN1 2.7810 0 0.909 0.094
7 TUBA1B 3.1534 0 1.000 0.310
7 HMGB2 3.1877 0 1.000 0.424
CD4+ T

We can use IL7R and S100A4 expression to identify the memory CD4+ T cells in clusters 0 & 2. IL7R and CCR7 identify the naive CD4+ T cells in the adjacent cluster 6.

p42 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "IL7R", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p43 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "S100A4", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p44 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "CCR7", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p42 | p43 | p44) / p41

CD8+ T

Next we reveal the CD8+ T cells in clusters 1 and 3 with CD8A, as per usual.

p45 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "CD8A", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p45 / p41

T-reg

The T-reg cluster, cluster 5, is identified using TIGIT and FOXP3.

p46 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "TIGIT", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p47 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "FOXP3", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p46 | p47) / p41

NK

The natural killers can be found in cluster 4 through their expression of PRF1 and NKG7. The NKG7 expression also confirms the identities of the CD8+ T cells we just annotated.

p48 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "PRF1", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p49 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "NKG7", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p48 | p49) / p41

Proliferating T-reg

The tiny proliferating T-reg population in cluster 7 is characterized by TOP2A.

p50 <- FeaturePlot(nkt_norm, reduction = "tsne", features = "TOP2A", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p50 / p41

Visualization

We add final cell labels to our 8 cell clusters.

nkt_norm$label <- case_when(nkt_norm$seurat_clusters == 0 ~ "Memory CD4+ T", 
                            nkt_norm$seurat_clusters == 1 ~ "CD8+ T",
                            nkt_norm$seurat_clusters == 2 ~ "Memory CD4+ T",
                            nkt_norm$seurat_clusters == 3 ~ "CD8+ T",
                            nkt_norm$seurat_clusters == 4 ~ "NK",
                            nkt_norm$seurat_clusters == 5 ~ "T-reg", 
                            nkt_norm$seurat_clusters == 6 ~ "Naive CD4+ T", 
                            nkt_norm$seurat_clusters == 7 ~ "Proliferating T-reg")
Idents(nkt_norm) <- "label"
p51a <- DimPlot(nkt_norm, reduction = "tsne", pt.size = 1.5) + 
        scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        theme(plot.title = element_blank()) + 
        guides(color = guide_legend(nrow = 2, override.aes = list(size = 4)))
p51a

Here’s the marker genes.

nkt_norm_markers2 <- FindAllMarkers(nkt_norm, 
                                    logfc.threshold = .5, 
                                    test.use = "wilcox", 
                                    only.pos = TRUE, 
                                    random.seed = 629, 
                                    verbose = FALSE) %>% 
                      filter(p_val_adj < .05) %>% 
                      group_by(cluster) %>% 
                      arrange(desc(avg_log2FC)) %>% 
                      slice_head(n = 5)
p51b <- DotPlot(nkt_norm, features = unique(nkt_norm_markers2$gene), dot.scale = 10) + 
        scale_color_gradientn(colors = paletteer_d("wesanderson::Zissou1")) +
        labs(color = "Expression", size = "% Expressed") + 
        theme(axis.text.x = element_text(angle = 90, size = 10, vjust = 0.5), 
              legend.position = "right", legend.justification = "center", 
              panel.border = element_rect(fill = NA, size = 1, color = "black"), 
              axis.line = element_blank(), 
              legend.title = element_text(size = 14), 
              axis.title.y = element_blank(), 
              axis.title.x = element_blank(), 
              axis.text.y = element_text(size = 14)) + 
        guides(color = guide_colorbar(title.position = "top", 
                                      barheight = unit(3, units = "cm"), title.hjust = 0.5), 
               size = guide_legend(title.position = "top", title.hjust = 0.5))
p51b

Ductal Cells

Reclustering

We use KRT8 expression to show the ductal cells residing in clusters 5 and 9. We note that some regions of clusters 5 and 9 have no KRT8 expression, which likely means that they are composed of different cell types.

p52 <- FeaturePlot(pdac, reduction = "tsne", features = "KRT8", pt.size = 0.75) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p52 / p2

We run SCISSORS, then use a Wilcoxon differential expression test to determine potential markers for each cluster.

ductal <- ReclusterCells(pdac, 
                         which.clust = list(5, 9), 
                         merge.clusters = TRUE, 
                         n.HVG = 4000, 
                         n.PC = 20, 
                         k.vals = c(20, 30, 40, 50), nn.metric = "euclidean", 
                         resolution.vals = c(.2, .3, .4), 
                         redo.embedding = TRUE, 
                         random.seed = 629)
ductal_markers <- FindAllMarkers(ductal, 
                                 logfc.threshold = .5, 
                                 min.diff.pct = .2, 
                                 only.pos = TRUE, 
                                 verbose = FALSE, 
                                 random.seed = 629) %>% 
                  filter(p_val_adj < .05)
ductal_markers %>% 
  dplyr::select(cluster, gene, avg_log2FC, p_val_adj, pct.1, pct.2) %>% 
  group_by(cluster) %>% 
  top_n(n = 3, wt = avg_log2FC) %>% 
  kbl(booktabs = TRUE, digits = 4) %>% 
  kable_minimal("hover", full_width = FALSE)
## [1] "Reclustering cells in clusters 5, 9 using k = 50 & resolution = 0.2; S = 0.537"
cluster gene avg_log2FC p_val_adj pct.1 pct.2
0 MUCL3 2.0586 0 0.823 0.204
0 SLPI 1.9466 0 0.976 0.698
0 PSCA 1.8493 0 0.705 0.208
1 MUC1 1.0754 0 0.874 0.581
1 PLCG2 1.5615 0 0.464 0.173
1 LYZ 1.5575 0 0.873 0.614
2 CELA3A 6.7301 0 0.796 0.053
2 CTRB1 6.5305 0 0.741 0.058
2 CTRB2 8.2024 0 0.847 0.125
3 SERPING1 3.1176 0 0.996 0.266
3 CLU 3.5991 0 1.000 0.340
3 SPP1 5.3722 0 0.992 0.416
4 S100A2 4.4199 0 0.959 0.109
4 CST1 3.6054 0 0.497 0.012
4 PLAT 3.2459 0 0.782 0.126
5 APOA4 5.4298 0 0.698 0.002
5 APOA1 5.8060 0 0.746 0.007
5 ALDOB 4.3565 0 0.968 0.043
6 CRISP3 4.3529 0 0.930 0.022
6 CRP 3.6976 0 0.789 0.050
6 TCN1 4.2364 0 0.895 0.119

Again, we’ll run Fit-SNE on the reclustered cells.

duct_pc <- Embeddings(ductal, reduction = "pca")
# import data
duct_pc = r.duct_pc
# run Fit-SNE
affin_duct = PerplexityBasedNN(duct_pc, perplexity=30, random_state=629)
init = initialization.pca(duct_pc, random_state=629)
tsne_duct = TSNEEmbedding(init, affin_duct, negative_gradient_method='fft')
embed_d1 = tsne_duct.optimize(n_iter=250, exaggeration=10, momentum=0.6)
embed_d2 = embed_d1.optimize(n_iter=750, exaggeration=1, momentum=0.8)

We pull the results into R, making sure to save the Barnes-Hut t-SNE results in another reduction slot.

embed_duct <- as.matrix(py$embed_d2)
rownames(embed_duct) <- colnames(ductal)
ductal@reductions$bh_tsne <- ductal@reductions$tsne
ductal@reductions$tsne<- CreateDimReducObject(embeddings = embed_duct, 
                                              key = "FitSNE_", 
                                              assay = "SCT", 
                                              global = TRUE)
p53 <- DimPlot(ductal, reduction = "tsne", pt.size = 1.5) + 
       scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p53

Cell Type Identification

Lipid Processing

We use ANPEP & FABP1 expression to identify the lipid processing ductal cells in cluster 6.

p54 <- FeaturePlot(ductal, reduction = "tsne", features = "ANPEP", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p55 <- FeaturePlot(ductal, reduction = "tsne", features = "FABP1", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p54 | p55) / p53

Secretory

Expression of SOD3 and CFTR reveals the secretory cells in cluster 3.

p56 <- FeaturePlot(ductal, reduction = "tsne", features = "SOD3", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p57 <- FeaturePlot(ductal, reduction = "tsne", features = "CFTR", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p56 | p57) / p53

Classical 1

We use TFF1 and TFF2 expression to annotate the classical 1 epithelial cells in clusters 0 and 1. We can also see that the two classical 1 clusters are split by the sample from which the cells originate. Going forward, we’ll simply label both clusters as classical 1.

p58 <- FeaturePlot(ductal, reduction = "tsne", features = "TFF1", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p59 <- FeaturePlot(ductal, reduction = "tsne", features = "TFF2", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p60 <- DimPlot(ductal, reduction = "tsne", group.by = "sample", pt.size = 1.5) + 
       scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "Sample") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p58 | p60 | p59) / p53

Classical 2

The classical 2 cells are located in cluster 6, as evidenced by their expression of CRISP3.

p61 <- FeaturePlot(ductal, reduction = "tsne", features = "CRISP3", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p61 / p53

Basal-like

The basal compartment weights from DECODER are highest in cluster 4, which we will denote as being composed of basal-like PDAC.

p62 <- FeaturePlot(ductal, reduction = "tsne", features = "basal") + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "Basal") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p62 / p53

Acinar

Lastly, we show that cluster 2 is composed of acinar cells using CTRB2.

p63 <- FeaturePlot(ductal, reduction = "tsne", features = "CTRB2", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p63 / p53

Visualization

We add final cluster labels to our Seurat object and visualize the results.

ductal$label <- case_when(ductal$seurat_clusters == 0 ~ "Classical 1", 
                          ductal$seurat_clusters == 1 ~ "Classical 1", 
                          ductal$seurat_clusters == 2 ~ "Acinar", 
                          ductal$seurat_clusters == 3 ~ "Secretory", 
                          ductal$seurat_clusters == 4 ~ "Basal", 
                          ductal$seurat_clusters == 5 ~ "Lipid Proc.", 
                          ductal$seurat_clusters == 6 ~ "Classical 2")
Idents(ductal) <- "label"
p64a <- DimPlot(ductal, reduction = "tsne",pt.size = 1.5) + 
        scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        theme(plot.title = element_blank()) + 
        guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p64a

Here’s the marker genes.

ductal_markers2 <- FindAllMarkers(ductal, 
                                  logfc.threshold = .5, 
                                  test.use = "wilcox", 
                                  only.pos = TRUE, 
                                  random.seed = 629, 
                                  verbose = FALSE) %>% 
                   filter(p_val_adj < .05) %>% 
                   group_by(cluster) %>% 
                   arrange(desc(avg_log2FC)) %>% 
                   slice_head(n = 5)
p64b <- DotPlot(ductal, features = unique(ductal_markers2$gene), dot.scale = 10) + 
        scale_color_gradientn(colors = paletteer_d("wesanderson::Zissou1")) +
        labs(color = "Expression", size = "% Expressed") + 
        theme(axis.text.x = element_text(angle = 90, size = 12, vjust = 0.5), 
              legend.position = "right", legend.justification = "center", 
              panel.border = element_rect(fill = NA, size = 1, color = "black"), 
              axis.line = element_blank(), 
              legend.title = element_text(size = 14), 
              axis.title.y = element_blank(), 
              axis.title.x = element_blank(), 
              axis.text.y = element_text(size = 14)) + 
        guides(color = guide_colorbar(title.position = "top", 
                                      barheight = unit(3, units = "cm"), title.hjust = 0.5), 
               size = guide_legend(title.position = "top", title.hjust = 0.5))
p64b

Plasma Cells & Plasmacytoid DCs

We use JCHAIN (denoted IGJ in Elyada et al) to reveal the Plasma cells in cluster 10, and IRF7 to identify the plasmacytoid DCs in cluster 11.

p65 <- FeaturePlot(pdac, reduction = "tsne", features = "JCHAIN", pt.size = 0.75) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "JCHAIN (IGJ)") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p66 <- FeaturePlot(pdac, reduction = "tsne", features = "IRF7", pt.size = 0.75) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "IRF7") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p65 | p66) / p2

B Cells

We can identify the B cells in cluster 4 using joint expression of MS4A1 and CD79A. The cluster is split into two subclusters by tissue type: adjacent normal and PDAC. While it would be interesting to determine the genetic drivers of that separation, it’s somewhat outside of our scope here.

p67 <- FeaturePlot(pdac, reduction = "tsne", features = "MS4A1", pt.size = 0.75) +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "MS4A1") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p68 <- FeaturePlot(pdac, reduction = "tsne", features = "CD79A", pt.size = 0.75) +
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "CD79A") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p69 <- DimPlot(pdac, reduction = "tsne", group.by = "condition", pt.size = 0.75) + 
       scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "Tissue Type") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p67 | p69 | p68) / p2

Myeloid Cells

Lastly, we’ll split up the myeloid population by tissue condition (PDAC vs. adjacent normal) just like we did with the NK / T cells. We’ll run SCISSORS, annotate the clusters, and visualize the results.

Tumor

First we’ll attempt to assign broad cell type labels to each of the four putative myeloid clusters. We’ll use the marker genes from Elyada et al once again.

myo_tumor <- subset(pdac, subset = seurat_clusters %in% c(1, 2, 7) & condition == "PDAC")
p70 <- DimPlot(myo_tumor, reduction = "tsne", pt.size = 1.5) + 
       scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       theme(plot.title = element_blank()) + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p70

Cluster 1 appears to be composed of our resident & alternatively activated macrophages due to its expression of CD14 & C1QA and SPP1, respectively.

p71 <- FeaturePlot(myo_tumor, reduction = "tsne", features = "CD14", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "CD14") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p72 <- FeaturePlot(myo_tumor, reduction = "tsne", features = "C1QA", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "C1QA") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p73 <- FeaturePlot(myo_tumor, reduction = "tsne", features = "SPP1", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "SPP1") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p71 | p72 | p73) / p70

We can use LYZ and S100A8 expression to reveal the classic monocytes and neutrophils in cluster 2.

p74 <- FeaturePlot(myo_tumor, reduction = "tsne", features = "LYZ", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "LYZ") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p75 <- FeaturePlot(myo_tumor, reduction = "tsne", features = "S100A8", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "S100A8") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p74 | p75) / p70

Lastly, we show that cluster 6 contains our various DC subtypes through its expression of FCER1A, a canonical dendritic cell marker.

p76 <- FeaturePlot(myo_tumor, reduction = "tsne", features = "FCER1A", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "FCER1A") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p76 / p70

Reclustering

We’ll start with the Macrophages & Monocytes, since the DC populations are small and are best dealt with on their own.

myo_reclust <- ReclusterCells(myo_tumor, 
                              which.clust = c(1, 2), 
                              n.PC = 15, 
                              merge.clusters = TRUE, 
                              k.vals = c(40, 50, 60), 
                              resolution.vals = c(.2, .3, .4), 
                              n.HVG = 4000, 
                              redo.embedding = TRUE, 
                              random.seed = 629)
dc_reclust <- ReclusterCells(myo_tumor, 
                             which.clust = 7, 
                             n.PC = 15, 
                             k.vals = c(20, 30, 40, 50), 
                             resolution.vals = c(.3, .4, .5), 
                             n.HVG = 4000, 
                             nn.metric = "euclidean", 
                             redo.embedding = TRUE, 
                             random.seed = 629)
## [1] "Reclustering cells in clusters 1, 2 using k = 60 & resolution = 0.2; S = 0.337"
## [1] "Reclustering cells in cluster 7 using k = 30 & resolution = 0.4; S = 0.429"

We’ll again run Fit-SNE on our reclustered cells.

mono_tumor_pc <- Embeddings(myo_reclust, "pca")
dc_tumor_pc <- Embeddings(dc_reclust, "pca")
# import data
mono_pc = r.mono_tumor_pc
dc_pc = r.dc_tumor_pc
# Fit-SNE - monocytes & macrophages
affin_mono = PerplexityBasedNN(mono_pc, perplexity=30, metric='cosine', random_state=629)
init = initialization.pca(mono_pc, random_state=629)
tsne_mono = TSNEEmbedding(init, affin_mono, negative_gradient_method='fft')
embed_mono1 = tsne_mono.optimize(n_iter=250, exaggeration=10, momentum=0.6)
embed_mono2 = embed_mono1.optimize(n_iter=750, exaggeration=1, momentum=0.8)
# Fit-SNE - DC
affin_dc = PerplexityBasedNN(dc_pc, perplexity=30, random_state=629)
init = initialization.pca(dc_pc, random_state=629)
tsne_dc = TSNEEmbedding(init, affin_dc, negative_gradient_method='fft')
embed_dc1 = tsne_dc.optimize(n_iter=250, exaggeration=12, momentum=0.6)
embed_dc2 = embed_dc1.optimize(n_iter=750, exaggeration=1, momentum=0.8)

We pull the results back into R and visualize them.

embed_mono <- as.matrix(py$embed_mono2)
rownames(embed_mono) <- colnames(myo_reclust)
myo_reclust@reductions$bh_tsne <- myo_reclust@reductions$tsne
myo_reclust@reductions$tsne<- CreateDimReducObject(embeddings = embed_mono, 
                                                   key = "FitSNE_", 
                                                   assay = "SCT",
                                                   global = TRUE)
p77 <- DimPlot(myo_reclust, reduction = "tsne", pt.size = 1.5) + 
       scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       theme(plot.title = element_blank()) + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p77

embed_dc <- as.matrix(py$embed_dc2)
rownames(embed_dc) <- colnames(dc_reclust)
dc_reclust@reductions$bh_tsne <- dc_reclust@reductions$tsne
dc_reclust@reductions$tsne<- CreateDimReducObject(embeddings = embed_dc, 
                                                  key = "FitSNE_", 
                                                  assay = "SCT",
                                                  global = TRUE)
p78 <- DimPlot(dc_reclust, reduction = "tsne", pt.size = 1.5) + 
       scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       theme(plot.title = element_blank()) + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p78

Cell Type Identification

Monoctyes, Macrophages, & Neutrophils

First we ID the neutrophils in cluster 2 using S100A8 and S100A9 - marker genes used by Elyada et al.

p79 <- FeaturePlot(myo_reclust, reduction = "tsne", features = "S100A8", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "S100A8") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p80 <- FeaturePlot(myo_reclust, reduction = "tsne", features = "S100A9", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "S100A9") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p79 | p80) / p77

We can identify the classical monocytes in cluster 1 through their expression of CD14 and lack of expression of CD16 aka FCGR3A, expression of which, alongside that of MS4A7, reveals the group of CD16+ monocytes in cluster 4. Finally, expression of those genes as well as S100A10 allows us to defined cluster 5 as containing intermediate monocytes.

p81 <- FeaturePlot(myo_reclust, reduction = "tsne", features = "CD14", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "CD14") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p82 <- FeaturePlot(myo_reclust, reduction = "tsne", features = "FCGR3A", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "FCGR3A (CD16)") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p83 <- FeaturePlot(myo_reclust, reduction = "tsne", features = "MS4A7", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "MS4A7") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p84 <- FeaturePlot(myo_reclust, reduction = "tsne", features = "S100A10", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "S100A10") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p81 | p82 | p83 | p84) / p77

Expression of C1QA, APOE, and SPP1 show us the resident and alternatively activated macrophages in clusters 0 and 3, respectively.

p85 <- FeaturePlot(myo_reclust, reduction = "tsne", features = "C1QA", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "C1QA") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p86 <- FeaturePlot(myo_reclust, reduction = "tsne", features = "APOE", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "APOE") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p87 <- FeaturePlot(myo_reclust, reduction = "tsne", features = "SPP1", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "SPP1") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p85 | p86 | p87) / p77

We add cell labels to our Seurat object, then we’re off to the DCs.

myo_reclust$label <- case_when(myo_reclust$seurat_clusters == 0 ~ "Resident Macrophage", 
                               myo_reclust$seurat_clusters == 1 ~ "Classical Monocyte", 
                               myo_reclust$seurat_clusters == 2 ~ "Neutrophil", 
                               myo_reclust$seurat_clusters == 3 ~ "Alt. Activated Macrophage", 
                               myo_reclust$seurat_clusters == 4 ~ "CD16+ Monocyte", 
                               myo_reclust$seurat_clusters == 5 ~ "Intermediate Monocyte")
Idents(myo_reclust) <- "label"
Dendritic Cells

We can use CLEC9A to annotate the cDC1 population in cluster 5.

p88 <- FeaturePlot(dc_reclust, reduction = "tsne", features = "CLEC9A", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "CLEC9A") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p88 / p78

High and low expression of CD1A and CD207 reveal the Langerhans-like DCB and DCA cells in clusters 3 and 4, respectively.

p89 <- FeaturePlot(dc_reclust, reduction = "tsne", features = "CD1A", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "CD1A") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p90 <- FeaturePlot(dc_reclust, reduction = "tsne", features = "CD207", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "CD207") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p89 | p90) / p78

Next we use LAMP3 to identify the activated DCs in cluster 6.

p91 <- FeaturePlot(dc_reclust, reduction = "tsne", features = "LAMP3", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "LAMP3") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p91 / p78

Lastly, we use expression of two canonical cDC2 marker genes / transcription factors to identify clusters 0, 1, and 2 as cDC2 cells, which are split by sample ID.

p92 <- FeaturePlot(dc_reclust, reduction = "tsne", features = "CLEC10A", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p93 <- FeaturePlot(dc_reclust, reduction = "tsne", features = "KLF4", pt.size = 1.5) + 
       scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
p94 <- DimPlot(dc_reclust, reduction = "tsne", group.by = "sample", pt.size = 1.5) + 
       scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "Sample") + 
       theme_yehlab() + 
       NoLegend() + 
       theme(axis.title = element_blank())
(p92 | p94 | p93) / p78

We add final subcluster cell type labels to our Seurat object, then we’re off to the adjacent normal myeloid cells.

dc_reclust$label <- case_when(dc_reclust$seurat_clusters == 0 ~ "cDC2", 
                              dc_reclust$seurat_clusters == 1 ~ "cDC2", 
                              dc_reclust$seurat_clusters == 2 ~ "cDC2", 
                              dc_reclust$seurat_clusters == 3 ~ "Langerhans-like DCB", 
                              dc_reclust$seurat_clusters == 4 ~ "Langerhans-like DCA", 
                              dc_reclust$seurat_clusters == 5 ~ "cDC1", 
                              dc_reclust$seurat_clusters == 6 ~ "Activated DC")
Idents(dc_reclust) <- "label"

Visualization

Monocytes & Neutrophils
p95a <- DimPlot(myo_reclust, reduction = "tsne", pt.size = 1.5) + 
        scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        theme(plot.title = element_blank()) + 
        guides(color = guide_legend(nrow = 2, override.aes = list(size = 4)))
p95a

Here’s the marker genes.

myo_reclust_markers2 <- FindAllMarkers(myo_reclust, 
                                       logfc.threshold = .5, 
                                       test.use = "wilcox", 
                                       only.pos = TRUE, 
                                       random.seed = 629, 
                                       verbose = FALSE) %>% 
                        filter(p_val_adj < .05) %>% 
                        group_by(cluster) %>% 
                        arrange(desc(avg_log2FC)) %>% 
                        slice_head(n = 5)
p95b <- DotPlot(myo_reclust, features = unique(myo_reclust_markers2$gene), dot.scale = 10) + 
        scale_color_gradientn(colors = paletteer_d("wesanderson::Zissou1")) +
        labs(color = "Expression", size = "% Expressed") + 
        theme(axis.text.x = element_text(angle = 90, size = 9, vjust = 0.5), 
              legend.position = "right", legend.justification = "center", 
              panel.border = element_rect(fill = NA, size = 1, color = "black"), 
              axis.line = element_blank(), 
              legend.title = element_text(size = 14), 
              axis.title.y = element_blank(), 
              axis.title.x = element_blank(), 
              axis.text.y = element_text(size = 14)) + 
        guides(color = guide_colorbar(title.position = "top", 
                                      barheight = unit(3, units = "cm"), title.hjust = 0.5), 
               size = guide_legend(title.position = "top", title.hjust = 0.5))
p95b

DCs
p96a <- DimPlot(dc_reclust, reduction = "tsne", pt.size = 1.5) + 
        scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        theme(plot.title = element_blank()) + 
        guides(color = guide_legend(nrow = 2, override.aes = list(size = 3)))
p96a

Here’s the marker genes.

dc_reclust_markers2 <- FindAllMarkers(dc_reclust, 
                                      logfc.threshold = .5, 
                                      test.use = "wilcox", 
                                      only.pos = TRUE, 
                                      random.seed = 629, 
                                      verbose = FALSE) %>% 
                       filter(p_val_adj < .05) %>% 
                       group_by(cluster) %>% 
                       arrange(desc(avg_log2FC)) %>% 
                       slice_head(n = 5)
p96b <- DotPlot(dc_reclust, features = unique(dc_reclust_markers2$gene), dot.scale = 8) + 
        scale_color_gradientn(colors = paletteer_d("wesanderson::Zissou1")) +
        labs(color = "Expression", size = "% Expressed") + 
        theme(axis.text.x = element_text(angle = 90, size = 9, vjust = 0.5), 
              legend.position = "right", legend.justification = "center", 
              panel.border = element_rect(fill = NA, size = 1, color = "black"), 
              axis.line = element_blank(), 
              legend.title = element_text(size = 14), 
              axis.title.y = element_blank(), 
              axis.title.x = element_blank(), 
              axis.text.y = element_text(size = 14)) + 
        guides(color = guide_colorbar(title.position = "top", 
                                      barheight = unit(3, units = "cm"), title.hjust = 0.5), 
               size = guide_legend(title.position = "top", title.hjust = 0.5))
p96b

Adjacent Normal

We have the same four clusters as in the tumor tissue - 1, 2, & 7 - and we’ll run the same analysis steps.

myo_norm <- subset(pdac, subset = seurat_clusters %in% c(1, 2, 7) & condition == "AdjNorm")

Reclustering

myo_norm_reclust <- ReclusterCells(myo_norm, 
                                   which.clust = c(1, 2), 
                                   n.PC = 15, 
                                   merge.clusters = TRUE, 
                                   k.vals = c(20, 30, 40), 
                                   resolution.vals = c(.1, .2), 
                                   n.HVG = 4000, 
                                   redo.embedding = TRUE, 
                                   random.seed = 629)
dc_norm_reclust <- ReclusterCells(myo_norm, 
                                  which.clust = 7, 
                                  n.PC = 15, 
                                  k.vals = c(20, 30, 40, 50), 
                                  resolution.vals = c(.3, .4, .5), 
                                  n.HVG = 4000, 
                                  nn.metric = "euclidean", 
                                  redo.embedding = TRUE, 
                                  random.seed = 629)
## [1] "Reclustering cells in clusters 1, 2 using k = 20 & resolution = 0.2; S = 0.328"
## [1] "Reclustering cells in cluster 7 using k = 30 & resolution = 0.3; S = 0.445"

For the last time, we run Fit-SNE in order to obtain a better embedding.

mono_norm_pc <- Embeddings(myo_norm_reclust, "pca")
dc_norm_pc <- Embeddings(dc_norm_reclust, "pca")
# import data
mono_pc = r.mono_norm_pc
dc_pc = r.dc_norm_pc
# Fit-SNE - monocytes
affin_mono = PerplexityBasedNN(mono_pc, perplexity=30, metric='cosine', random_state=629)
init = initialization.pca(mono_pc, random_state=629)
tsne_mono = TSNEEmbedding(init, affin_mono, negative_gradient_method='fft')
embed_mono1 = tsne_mono.optimize(n_iter=250, exaggeration=10, momentum=0.6)
embed_mono2 = embed_mono1.optimize(n_iter=750, exaggeration=1, momentum=0.8)
# Fit-SNE - DC
affin_dc = PerplexityBasedNN(dc_pc, perplexity=30, metric='cosine', random_state=629)
init = initialization.pca(dc_pc, random_state=629)
tsne_dc = TSNEEmbedding(init, affin_dc, negative_gradient_method='fft')
embed_dc1 = tsne_dc.optimize(n_iter=250, exaggeration=8, momentum=0.6)
embed_dc2 = embed_dc1.optimize(n_iter=750, exaggeration=1, momentum=0.8)

We pull the results back into R and visualize them.

embed_mono <- as.matrix(py$embed_mono2)
rownames(embed_mono) <- colnames(myo_norm_reclust)
myo_norm_reclust@reductions$bh_tsne <- myo_norm_reclust@reductions$tsne
myo_norm_reclust@reductions$tsne<- CreateDimReducObject(embeddings = embed_mono, 
                                                        key = "FitSNE_", 
                                                        assay = "SCT",
                                                        global = TRUE)
p97 <- DimPlot(myo_norm_reclust, reduction = "tsne", pt.size = 1.5) + 
       scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       theme(plot.title = element_blank()) + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p97

embed_dc <- as.matrix(py$embed_dc2)
rownames(embed_dc) <- colnames(dc_norm_reclust)
dc_norm_reclust@reductions$bh_tsne <- dc_norm_reclust@reductions$tsne
dc_norm_reclust@reductions$tsne<- CreateDimReducObject(embeddings = embed_dc, 
                                                       key = "FitSNE_", 
                                                       assay = "SCT",
                                                       global = TRUE)
p98 <- DimPlot(dc_norm_reclust, reduction = "tsne", pt.size = 1.5) + 
       scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
       labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
       theme_yehlab() + 
       theme(plot.title = element_blank()) + 
       guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p98

Cell Type Identification

Monocytes, Macrophages, & Neutrophils

We use high S100A8 and S100A9 expression to define the neutrophils in cluster 4.

p99 <- FeaturePlot(myo_norm_reclust, reduction = "tsne", features = "S100A8", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p100 <- FeaturePlot(myo_norm_reclust, reduction = "tsne", features = "S100A9", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
(p99 | p100) / p97

Next up are the classical monocytes in clusters 0 and 3, split by sample.

p101 <- FeaturePlot(myo_norm_reclust, reduction = "tsne", features = "LYZ", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p102 <- FeaturePlot(myo_norm_reclust, reduction = "tsne", features = "CD14", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p103 <- DimPlot(myo_norm_reclust, reduction = "tsne", group.by = "sample", pt.size = 1.5) + 
        scale_color_manual(values = paletteer_d("miscpalettes::brightPastel")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2", title = "Sample") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
(p101 | p102 | p103) / p97

C1QA and APOE show us the resident macrophages in clusters 1 and 2.

p104 <- FeaturePlot(myo_norm_reclust, reduction = "tsne", features = "C1QA", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p105 <- FeaturePlot(myo_norm_reclust, reduction = "tsne", features = "APOE", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
(p104 | p105) / p97

Lastly, it seems we have a small group of CD8+ T cells in cluster 5 that snuck into the myeloid cluster, as defined by their expression of CD3D (marking them as NK / T cells), and CD8A & NKG7. I don’t believe they’re NK cells as they do not express PRF1 or GZMB.

p106 <- FeaturePlot(myo_norm_reclust, reduction = "tsne", features = "CD3D") + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p107 <- FeaturePlot(myo_norm_reclust, reduction = "tsne", features = "CD8A") + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p108 <- FeaturePlot(myo_norm_reclust, reduction = "tsne", features = "NKG7") + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
(p106 | p107 | p108) / p97

We add labels to our clusters.

myo_norm_reclust$label <- case_when(myo_norm_reclust$seurat_clusters == 0 ~ "Classical Monocyte", 
                                    myo_norm_reclust$seurat_clusters == 1 ~ "Resident Macrophage", 
                                    myo_norm_reclust$seurat_clusters == 2 ~ "Resident Macrophage", 
                                    myo_norm_reclust$seurat_clusters == 3 ~ "Classical Monocyte", 
                                    myo_norm_reclust$seurat_clusters == 4 ~ "Neutrophil",
                                    myo_norm_reclust$seurat_clusters == 5 ~ "CD8+ T")
Idents(myo_norm_reclust) <- "label"
Dendritic Cells

We annotate cluster 1 as conventional DC1 and cluster 0 as conventional DC2 through mutually exclusive expression of the canonical markers CLEC9A and CLEC10A, respectively.

p109 <- FeaturePlot(dc_norm_reclust, reduction = "tsne", features = "CLEC9A", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
p110 <- FeaturePlot(dc_norm_reclust, reduction = "tsne", features = "CLEC10A", pt.size = 1.5) + 
        scale_color_gradientn(colors = wesanderson::wes_palette("Zissou1")) + 
        labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
        theme_yehlab() + 
        NoLegend() + 
        theme(axis.title = element_blank())
(p109 | p110) / p98

Labels are added to our adjacent normal tissue DC Seurat object.

dc_norm_reclust$label <- case_when(dc_norm_reclust$seurat_clusters == 0 ~ "cDC2", 
                                   dc_norm_reclust$seurat_clusters == 1 ~ "cDC2", 
                                   dc_norm_reclust$seurat_clusters == 2 ~ "cDC1")
Idents(dc_norm_reclust) <- "label"

Visualization

Here are the final annotations for the adjacent normal tissue myeloid population.

p111a <- DimPlot(myo_norm_reclust, reduction = "tsne", pt.size = 1.5) + 
         scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
         labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
         theme_yehlab() + 
         theme(plot.title = element_blank()) + 
         guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p111a

And here’s their marker genes.

myo_norm_reclust_markers2 <- FindAllMarkers(myo_norm_reclust, 
                                            logfc.threshold = .5, 
                                            test.use = "wilcox", 
                                            only.pos = TRUE, 
                                            random.seed = 629, 
                                            verbose = FALSE) %>% 
                             filter(p_val_adj < .05) %>% 
                             group_by(cluster) %>% 
                             arrange(desc(avg_log2FC)) %>% 
                             slice_head(n = 5)
p111b <- DotPlot(myo_norm_reclust, features = unique(myo_norm_reclust_markers2$gene), dot.scale = 10) + 
         scale_color_gradientn(colors = paletteer_d("wesanderson::Zissou1")) +
         labs(color = "Expression", size = "% Expressed") + 
         theme(axis.text.x = element_text(angle = 90, size = 12, vjust = 0.5), 
               legend.position = "right", legend.justification = "center", 
               panel.border = element_rect(fill = NA, size = 1, color = "black"), 
               axis.line = element_blank(), 
               legend.title = element_text(size = 14), 
               axis.title.y = element_blank(), 
               axis.title.x = element_blank(), 
               axis.text.y = element_text(size = 14)) + 
         guides(color = guide_colorbar(title.position = "top", 
                                       barheight = unit(3, units = "cm"), title.hjust = 0.5), 
                size = guide_legend(title.position = "top", title.hjust = 0.5))
p111b

Here’s the final DC annotations .

p112a <- DimPlot(dc_norm_reclust, reduction = "tsne", pt.size = 1.5) + 
         scale_color_manual(values = paletteer_d("ggsci::default_nejm")) + 
         labs(x = "Fit-SNE 1", y = "Fit-SNE 2") + 
         theme_yehlab() + 
         theme(plot.title = element_blank()) + 
         guides(color = guide_legend(nrow = 1, override.aes = list(size = 4)))
p112a

And here are their marker genes.

dc_norm_reclust_markers2 <- FindAllMarkers(dc_norm_reclust, 
                                           logfc.threshold = .5, 
                                           test.use = "wilcox", 
                                           only.pos = TRUE, 
                                           random.seed = 629, 
                                           verbose = FALSE) %>% 
                            filter(p_val_adj < .05) %>% 
                            group_by(cluster) %>% 
                            arrange(desc(avg_log2FC)) %>% 
                            slice_head(n = 5)
p112b <- DotPlot(dc_norm_reclust, features = unique(dc_norm_reclust_markers2$gene), dot.scale = 10) + 
         scale_color_gradientn(colors = paletteer_d("wesanderson::Zissou1")) +
         labs(color = "Expression", size = "% Expressed") + 
         theme(axis.text.x = element_text(angle = 90, size = 14, vjust = 0.5), 
               legend.position = "right", 
               legend.justification = "center", 
               panel.border = element_rect(fill = NA, size = 1, color = "black"), 
               axis.line = element_blank(), 
               legend.title = element_text(size = 16), 
               axis.title.y = element_blank(), 
               axis.title.x = element_blank(), 
               axis.text.y = element_text(size = 16)) + 
         guides(color = guide_colorbar(title.position = "top", 
                                       barheight = unit(3, units = "cm"), title.hjust = 0.5), 
                size = guide_legend(title.position = "top", title.hjust = 0.5))
p112b

Conclusions

Save Figures & Data

We’ll create a quick convenience function to help us save the figures.

SaveFigure <- function(my.plot = NULL, name = NULL, height = 8, width = 8) {
  if (is.null(plot) | is.null(name)) stop("You forgot some arguments.")
  # save figure as is - w/ axis labels, titles, etc. 
  dir <- "~/Desktop/R/SCISSORS/vignettes/figures_supp/Elyada"
  ggsave(my.plot, 
         filename = paste0(name, ".pdf"), 
         device = "pdf", 
         units = "in",
         path = dir, 
         height = height, 
         width = width) 
  # save "blank" figure w/ no labels, legends, etc.
  dir <- "~/Desktop/R/SCISSORS/vignettes/figures_pub/Elyada"
  plot_blank <- my.plot + 
                theme(axis.title = element_blank(), 
                      panel.border = element_blank(), 
                      plot.title = element_blank(), 
                      plot.subtitle = element_blank(), 
                      plot.caption = element_blank(), 
                      legend.position = "none")
  ggsave(plot_blank, 
         filename = paste0(name, ".pdf"), 
         device = "pdf", 
         units = "in",
         path = dir, 
         height = height, 
         width = width) 
}

This section isn’t worth reading; it’s here solely to prove that the figures we present in our publication were dynamically generated during the knitting of this document.

SaveFigure(my.plot = p0a, name = "Seurat_Clusters_tSNE")
SaveFigure(my.plot = p0b, name = "Seurat_Clusters_Sil_Score")
SaveFigure(my.plot = p0c, name = "Seurat_Clusters_Dotplot", height = 8, width = 12)
SaveFigure(my.plot = p1, name = "Seurat_Clusters_UMAP")
SaveFigure(my.plot = p2, name = "Seurat_Clusters_FitSNE")
SaveFigure(my.plot = p3, name = "SingleR_Annos_SC_Ref")
SaveFigure(my.plot = p4, name = "SingleR_Annos_Bulk_Ref")
SaveFigure(my.plot = p5, name = "CONICSmat_Annos")
SaveFigure(my.plot = p6, name = "DECODER_Basal")
SaveFigure(my.plot = p7, name = "DECODER_Classical")
SaveFigure(my.plot = p8, name = "DECODER_Exocrine")
SaveFigure(my.plot = p9, name = "DECODER_Endocrine")
SaveFigure(my.plot = p10, name = "DECODER_Immune")
SaveFigure(my.plot = p11, name = "DECODER_Normal_Stroma")
SaveFigure(my.plot = p12, name = "DECODER_Act_Stroma")
SaveFigure(my.plot = p13, name = "Fibro_All_Cells_COL1A1")
SaveFigure(my.plot = p14, name = "Fibro_All_Cells_COL3A1")
SaveFigure(my.plot = p15, name = "Fibro_All_Cells_LUM")
SaveFigure(my.plot = p16, name = "Fibro_All_Cells_DCN")
SaveFigure(my.plot = p17, name = "Fibro_SCISSORS_FitSNE")
SaveFigure(my.plot = p18, name = "Fibro_Endothelial_PLVAP")
SaveFigure(my.plot = p19, name = "Fibro_Perivascular_RGS5")
SaveFigure(my.plot = p20, name = "Fibro_VAM_iCAF")
SaveFigure(my.plot = p21, name = "Fibro_VAM_myCAF")
SaveFigure(my.plot = p22, name = "Fibro_VAM_apCAF")
SaveFigure(my.plot = p23a, name = "Fibro_Final_Labels")
SaveFigure(my.plot = p23b, name = "Fibro_Dotplot", height = 8, width = 12)
SaveFigure(my.plot = p24, name = "NKT_All_Cells_CD3D")
SaveFigure(my.plot = p25, name = "NKT_Tumor_SCISSORS_FitSNE")
SaveFigure(my.plot = p26, name = "NKT_Tumor_CD4T_IL7R")
SaveFigure(my.plot = p27, name = "NKT_Tumor_CD4T_CD69")
SaveFigure(my.plot = p28, name = "NKT_Tumor_Treg_IL2RA")
SaveFigure(my.plot = p29, name = "NKT_Tumor_Treg_FOXP3")
SaveFigure(my.plot = p30, name = "NKT_Tumor_Prolif_Treg_TOP2A")
SaveFigure(my.plot = p31, name = "NKT_Tumor_Mast_TPSAB1")
SaveFigure(my.plot = p32, name = "NKT_Tumor_NK_NKG7")
SaveFigure(my.plot = p33, name = "NKT_Tumor_NK_PRF1")
SaveFigure(my.plot = p34, name = "NKT_Tumor_CD8T_CD8A")
SaveFigure(my.plot = p35, name = "NKT_Tumor_CD8T_CD2")
SaveFigure(my.plot = p36, name = "NKT_Tumor_Intermediate_Mono_LYZ")
SaveFigure(my.plot = p37, name = "NKT_Tumor_Intermediate_Mono_HLADRA")
SaveFigure(my.plot = p38, name = "NKT_Tumor_Intermediate_Mono_CD74")
SaveFigure(my.plot = p39, name = "NKT_Tumor_Intermediate_Mono_HLADPB1")
SaveFigure(my.plot = p40a, name = "NKT_Tumor_Final_Labels")
SaveFigure(my.plot = p40b, name = "NKT_Tumor_Dotplot", height = 8, width = 12)
SaveFigure(my.plot = p41, name = "NKT_Norm_SCISSORS_FitSNE")
SaveFigure(my.plot = p42, name = "NKT_Norm_CD4T_IL7R")
SaveFigure(my.plot = p43, name = "NKT_Norm_CD4T_S100A4")
SaveFigure(my.plot = p44, name = "NKT_Norm_CD4T_CCR7")
SaveFigure(my.plot = p45, name = "NKT_Norm_CD8T_CD8A")
SaveFigure(my.plot = p46, name = "NKT_Norm_Treg_TIGIT")
SaveFigure(my.plot = p47, name = "NKT_Norm_Treg_FOXP3")
SaveFigure(my.plot = p48, name = "NKT_Norm_NK_PRF1")
SaveFigure(my.plot = p49, name = "NKT_Norm_NK_NKG7")
SaveFigure(my.plot = p50, name = "NKT_Norm_Prolif_Treg_TOP2A")
SaveFigure(my.plot = p51a, name = "NKT_Norm_Final_Labels")
SaveFigure(my.plot = p51b, name = "NKT_Norm_Dotplot", height = 8, width = 12)
SaveFigure(my.plot = p52, name = "Ductal_All_Cells_KRT8")
SaveFigure(my.plot = p53, name = "Ductal_SCISSORS_FitSNE")
SaveFigure(my.plot = p54, name = "Ductal_Lipid_Proc_ANPEP")
SaveFigure(my.plot = p55, name = "Ductal_Lipid_Proc_FABP1")
SaveFigure(my.plot = p56, name = "Ductal_Secretory_SOD3")
SaveFigure(my.plot = p57, name = "Ductal_Secretory_CFTR")
SaveFigure(my.plot = p58, name = "Ductal_Classical1_TFF1")
SaveFigure(my.plot = p59, name = "Ductal_Classical1_TFF2")
SaveFigure(my.plot = p60, name = "Ductal_Classical1_SampleID")
SaveFigure(my.plot = p61, name = "Ductal_Classical2_CRISP3")
SaveFigure(my.plot = p62, name = "Ductal_DECODER_Basal")
SaveFigure(my.plot = p63, name = "Ductal_Acinar_CTRB2")
SaveFigure(my.plot = p64a, name = "Ductal_Final_Labels")
SaveFigure(my.plot = p64b, name = "Ductal_Dotplot", height = 8, width = 12)
SaveFigure(my.plot = p65, name = "Plasma_All_Cells_IGJ")
SaveFigure(my.plot = p66, name = "Plasmacytoid_DC_All_Cells_IRF7")
SaveFigure(my.plot = p67, name = "B_All_Cells_MS4A1")
SaveFigure(my.plot = p68, name = "B_All_Cells_CD79A")
SaveFigure(my.plot = p69, name = "B_All_Cells_Tissue_Type")
SaveFigure(my.plot = p70, name = "Myeloid_Tumor_All_Cells_FitSNE")
SaveFigure(my.plot = p71, name = "Myeloid_Tumor_All_Cells_CD14")
SaveFigure(my.plot = p72, name = "Myeloid_Tumor_All_Cells_C1QA")
SaveFigure(my.plot = p73, name = "Myeloid_Tumor_All_Cells_SPP1")
SaveFigure(my.plot = p74, name = "Myeloid_Tumor_All_Cells_LYZ")
SaveFigure(my.plot = p75, name = "Myeloid_Tumor_All_Cells_S100A8")
SaveFigure(my.plot = p76, name = "Myeloid_Tumor_All_Cells_FCER1A")
SaveFigure(my.plot = p77, name = "Myeloid_Tumor_SCISSORS_FitSNE")
SaveFigure(my.plot = p78, name = "DC_Tumor_SCISSORS_FitSNE")
SaveFigure(my.plot = p79, name = "Myeloid_Tumor_Neutrophil_S100A8")
SaveFigure(my.plot = p80, name = "Myeloid_Tumor_Neutrophil_S100A9")
SaveFigure(my.plot = p81, name = "Myeloid_Tumor_Classic_Mono_CD14")
SaveFigure(my.plot = p82, name = "Myeloid_Tumor_CD16_Mono_FCGR3A")
SaveFigure(my.plot = p83, name = "Myeloid_Tumor_CD16_Mono_MS4A7")
SaveFigure(my.plot = p84, name = "Myeloid_Tumor_CD16_Mono_S100A10")
SaveFigure(my.plot = p85, name = "Myeloid_Tumor_Resident_Macro_C1QA")
SaveFigure(my.plot = p86, name = "Myeloid_Tumor_Alt_Activated_Macro_APOE")
SaveFigure(my.plot = p87, name = "Myeloid_Tumor_Alt_Activated_Macro_SPP1")
SaveFigure(my.plot = p88, name = "DC_Tumor_cDC1_CLEC9A")
SaveFigure(my.plot = p89, name = "DC_Tumor_Langerhans_DC_CD1A")
SaveFigure(my.plot = p90, name = "DC_Tumor_Langerhans_DC_CD207")
SaveFigure(my.plot = p91, name = "DC_Tumor_Activated_DC_LAMP3")
SaveFigure(my.plot = p92, name = "DC_Tumor_cDC2_CLEC10A")
SaveFigure(my.plot = p93, name = "DC_Tumor_cDC2_KLF4")
SaveFigure(my.plot = p94, name = "DC_Tumor_Sample_ID")
SaveFigure(my.plot = p95a, name = "Myeloid_Tumor_Final_Labels")
SaveFigure(my.plot = p95b, name = "Myeloid_Tumor_Dotplot", height = 8, width = 12)
SaveFigure(my.plot = p96a, name = "DC_Tumor_Final_Labels")
SaveFigure(my.plot = p96b, name = "DC_Tumor_Dotplot", height = 8, width = 12)
SaveFigure(my.plot = p97, name = "Myeloid_Norm_SCISSORS_FitSNE")
SaveFigure(my.plot = p98, name = "DC_Norm_SCISSORS_FitSNE")
SaveFigure(my.plot = p99, name = "Myeloid_Norm_Neutrophil_S100A8")
SaveFigure(my.plot = p100, name = "Myeloid_Norm_Neutrophil_S100A9")
SaveFigure(my.plot = p101, name = "Myeloid_Norm_Classic_Mono_LYZ")
SaveFigure(my.plot = p102, name = "Myeloid_Norm_Classic_Mono_CD14")
SaveFigure(my.plot = p103, name = "Myeloid_Norm_Sample_ID")
SaveFigure(my.plot = p104, name = "Myeloid_Norm_Resident_Macro_C1QA")
SaveFigure(my.plot = p105, name = "Myeloid_Norm_Alt_Activated_Macro_APOE")
SaveFigure(my.plot = p106, name = "Myeloid_Norm_CD8T_CD3D")
SaveFigure(my.plot = p107, name = "Myeloid_Norm_CD8T_CD8A")
SaveFigure(my.plot = p108, name = "Myeloid_Norm_CD8T_NKG7")
SaveFigure(my.plot = p109, name = "DC_Norm_cDC1_CLEC9A")
SaveFigure(my.plot = p110, name = "DC_Norm_cDC2_CLEC10A")
SaveFigure(my.plot = p111a, name = "Myeloid_Norm_Final_Labels")
SaveFigure(my.plot = p111b, name = "Myeloid_Norm_Dotplot", height = 8, width = 12)
SaveFigure(my.plot = p112a, name = "DC_Norm_Final_Labels")
SaveFigure(my.plot = p112b, name = "DC_Norm_Dotplot", height = 8, width = 12)

And of course:

sessionInfo()
## R version 4.0.4 (2021-02-15)
## Platform: x86_64-apple-darwin17.0 (64-bit)
## Running under: macOS Big Sur 10.16
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRblas.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## attached base packages:
## [1] parallel  stats4    stats     graphics  grDevices utils     datasets 
## [8] methods   base     
## 
## other attached packages:
##  [1] celldex_1.0.0               wesanderson_0.3.6          
##  [3] kableExtra_1.3.4            reticulate_1.18            
##  [5] CONICSmat_0.0.0.1           paletteer_1.3.0            
##  [7] latex2exp_0.5.0             patchwork_1.1.1            
##  [9] mixtools_1.2.0              SCISSORS_0.0.2.0           
## [11] SingleCellExperiment_1.12.0 data.table_1.14.0          
## [13] cluster_2.1.1               biomaRt_2.46.3             
## [15] decoderr_0.0.0.9000         SingleR_1.4.1              
## [17] SummarizedExperiment_1.20.0 Biobase_2.50.0             
## [19] GenomicRanges_1.42.0        GenomeInfoDb_1.26.7        
## [21] IRanges_2.24.1              S4Vectors_0.28.1           
## [23] BiocGenerics_0.36.0         MatrixGenerics_1.2.1       
## [25] matrixStats_0.58.0          ggplot2_3.3.3              
## [27] SeuratObject_4.0.0          Seurat_4.0.1               
## [29] dplyr_1.0.5                 VAM_0.5.2                  
## [31] Matrix_1.3-2                MASS_7.3-53.1              
## 
## loaded via a namespace (and not attached):
##   [1] utf8_1.2.1                    tidyselect_1.1.0             
##   [3] RSQLite_2.2.6                 AnnotationDbi_1.52.0         
##   [5] htmlwidgets_1.5.3             grid_4.0.4                   
##   [7] BiocParallel_1.24.1           Rtsne_0.15                   
##   [9] munsell_0.5.0                 codetools_0.2-18             
##  [11] ica_1.0-2                     statmod_1.4.35               
##  [13] scran_1.18.6                  future_1.21.0                
##  [15] miniUI_0.1.1.1                withr_2.4.2                  
##  [17] colorspace_2.0-0              highr_0.8                    
##  [19] knitr_1.32                    rstudioapi_0.13              
##  [21] ROCR_1.0-11                   tensor_1.5                   
##  [23] listenv_0.8.0                 labeling_0.4.2               
##  [25] GenomeInfoDbData_1.2.4        polyclip_1.10-0              
##  [27] pheatmap_1.0.12               farver_2.1.0                 
##  [29] bit64_4.0.5                   parallelly_1.24.0            
##  [31] vctrs_0.3.7                   generics_0.1.0               
##  [33] xfun_0.22                     BiocFileCache_1.14.0         
##  [35] squash_1.0.9                  R6_2.5.0                     
##  [37] phateR_1.0.7                  rsvd_1.0.3                   
##  [39] locfit_1.5-9.4                bitops_1.0-6                 
##  [41] spatstat.utils_2.1-0          cachem_1.0.4                 
##  [43] DelayedArray_0.16.3           assertthat_0.2.1             
##  [45] promises_1.2.0.1              scales_1.1.1                 
##  [47] gtable_0.3.0                  beachmat_2.6.4               
##  [49] globals_0.14.0                goftest_1.2-2                
##  [51] rlang_0.4.10                  systemfonts_1.0.1            
##  [53] splines_4.0.4                 lazyeval_0.2.2               
##  [55] prismatic_1.0.0               spatstat.geom_2.1-0          
##  [57] BiocManager_1.30.12           yaml_2.2.1                   
##  [59] reshape2_1.4.4                abind_1.4-5                  
##  [61] httpuv_1.5.5                  tools_4.0.4                  
##  [63] ellipsis_0.3.1                spatstat.core_2.0-0          
##  [65] jquerylib_0.1.3               RColorBrewer_1.1-2           
##  [67] ggridges_0.5.3                Rcpp_1.0.6                   
##  [69] plyr_1.8.6                    sparseMatrixStats_1.2.1      
##  [71] progress_1.2.2                zlibbioc_1.36.0              
##  [73] purrr_0.3.4                   RCurl_1.98-1.3               
##  [75] prettyunits_1.1.1             rpart_4.1-15                 
##  [77] openssl_1.4.3                 deldir_0.2-10                
##  [79] pbapply_1.4-3                 cowplot_1.1.1                
##  [81] zoo_1.8-9                     ggrepel_0.9.1                
##  [83] magrittr_2.0.1                RSpectra_0.16-0              
##  [85] scattermore_0.7               lmtest_0.9-38                
##  [87] RANN_2.6.1                    fitdistrplus_1.1-3           
##  [89] hms_1.0.0                     mime_0.10                    
##  [91] evaluate_0.14                 xtable_1.8-4                 
##  [93] XML_3.99-0.6                  gridExtra_2.3                
##  [95] compiler_4.0.4                tibble_3.1.1                 
##  [97] KernSmooth_2.23-18            crayon_1.4.1                 
##  [99] htmltools_0.5.1.1             segmented_1.3-3              
## [101] mgcv_1.8-34                   later_1.1.0.1                
## [103] tidyr_1.1.3                   DBI_1.1.1                    
## [105] ExperimentHub_1.16.0          dbplyr_2.1.1                 
## [107] rappdirs_0.3.3                igraph_1.2.6                 
## [109] pkgconfig_2.0.3               scuttle_1.0.4                
## [111] plotly_4.9.3                  spatstat.sparse_2.0-0        
## [113] xml2_1.3.2                    svglite_2.0.0                
## [115] bslib_0.2.4                   dqrng_0.2.1                  
## [117] webshot_0.5.2                 XVector_0.30.0               
## [119] rvest_1.0.0                   stringr_1.4.0                
## [121] digest_0.6.27                 sctransform_0.3.2            
## [123] RcppAnnoy_0.0.18              spatstat.data_2.1-0          
## [125] rmarkdown_2.7                 leiden_0.3.7                 
## [127] edgeR_3.32.1                  uwot_0.1.10                  
## [129] DelayedMatrixStats_1.12.3     curl_4.3                     
## [131] kernlab_0.9-29                shiny_1.6.0                  
## [133] lifecycle_1.0.0               nlme_3.1-152                 
## [135] jsonlite_1.7.2                BiocNeighbors_1.8.2          
## [137] limma_3.46.0                  viridisLite_0.4.0            
## [139] askpass_1.1                   fansi_0.4.2                  
## [141] pillar_1.6.0                  lattice_0.20-41              
## [143] fastmap_1.1.0                 httr_1.4.2                   
## [145] survival_3.2-10               interactiveDisplayBase_1.28.0
## [147] glue_1.4.2                    png_0.1-7                    
## [149] BiocVersion_3.12.0            bluster_1.0.0                
## [151] bit_4.0.4                     nnls_1.4                     
## [153] stringi_1.5.3                 sass_0.3.1                   
## [155] rematch2_2.1.2                blob_1.2.1                   
## [157] AnnotationHub_2.22.0          BiocSingular_1.6.0           
## [159] memoise_2.0.0                 irlba_2.3.3                  
## [161] future.apply_1.7.0
LS0tCnRpdGxlOiAiUmVjbHVzdGVyaW5nIEFuYWx5c2lzIG9mIENhbmNlci1Bc3NvY2lhdGVkIEZpYnJvYmxhc3RzIFVzaW5nIFNDSVNTT1JTIgpzdWJ0aXRsZTogIkphY2sgTGVhcnkiCmF1dGhvcjogCiAgLSAiVW5pdmVyc2l0eSBvZiBOb3J0aCBDYXJvbGluYSBhdCBDaGFwZWwgSGlsbCAtIExpbmViZXJnZXIgQ29tcHJlaGVuc2l2ZSBDYW5jZXIgQ2VudGVyIgogIC0gIlVuaXZlcnNpdHkgb2YgRmxvcmlkYSAtIERlcGFydG1lbnQgb2YgQmlvc3RhdGlzdGljcyIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiBwYXBlcgogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgZGZfcHJpbnQ6IGthYmxlCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSAiaG9sZCIsIAogICAgICAgICAgICAgICAgICAgICAgZmlnLmFsaWduID0gImNlbnRlciIpCnJldGljdWxhdGU6OnVzZV92aXJ0dWFsZW52KCJ+L0Rlc2t0b3AvUHl0aG9uL3NjaWVuY2UvdmVudi8iLCByZXF1aXJlZCA9IFRSVUUpCmBgYAoKIyBJbnRyb2R1Y3Rpb24KCkluIDIwMTcsIHRoZSBUdXZlc29uIExhYiBhdCBDb2xkIFNwcmluZyBIYXJib3IgQ2FuY2VyIENlbnRlciBwdWJsaXNoZWQgYSBwYXBlciB3cml0dGVuIGJ5IEVseWFkYSAqZXQgYWwqIHRoYXQgZGV0YWlsZWQgdGhlIGRpc2NvdmVyeSBvZiBjYW5jZXItYXNzb2NpYXRlZCBmaWJyb2JsYXN0cyAoQ0FGcykgaW4gbWljZS4gVGhlIHN1YnR5cGVzIHdlcmUgdGhlbiB2YWxpZGF0ZWQgaW4gaHVtYW4gc2FtcGxlcyBhZmZlY3RlZCB3aXRoIFBEQUMgaW4gYSBzdWJzZXF1ZW50IHBhcGVyIHJlbGVhc2VkIGluIDIwMTkuIEhlcmUgd2Ugd2lsbCB1c2UgU0NJU1NPUlMgdG8gaWRlbnRpZnkgdGhlIENBRiBzdWJ0eXBlcyB3aXRoaW4gdGhlIGxhcmdlciBzdHJvbWEgcG9wdWxhdGlvbiwgZmluZS1ncmFpbmVkIGltbXVuZSBjZWxsIHR5cGVzIHdpdGhpbiBicm9hZGx5LWRlZmluZWQgaW1tdW5lIGNsdXN0ZXJzLCBhbmQgZHVjdGFsICYgUERBQyBzdWJ0eXBlcyB3aXRoaW4gdGhlIGR1Y3RhbCBncm91cC4gWW91IGNhbiBpbnN0YWxsIFNDSVNTT1JTIGZyb20gW291ciBHaXRIdWIgcmVwb3NpdG9yeV0oaHR0cHM6Ly9naXRodWIuY29tL2pyLWxlYXJ5Ny9TQ0lTU09SUykuCgojIExpYnJhcmllcwoKIyMgUgoKYGBge3J9CmxpYnJhcnkoVkFNKSAgICAgICAgICMgc2luZ2xlIGNlbGwgR1NFQQpsaWJyYXJ5KGRwbHlyKSAgICAgICAjIHRpZHkgZGF0YSAKbGlicmFyeShTZXVyYXQpICAgICAgIyBzaW5nbGUgY2VsbCBpbmZyYXN0cnVjdHVyZQpsaWJyYXJ5KGdncGxvdDIpICAgICAjIHByZXR0eSBwbG90cwpsaWJyYXJ5KFNpbmdsZVIpICAgICAjIGNlbGwgdHlwZSBhc3NpZ25tZW50CmxpYnJhcnkoZGVjb2RlcnIpICAgICMgZGUgbm92byBkZWNvbnZvbHV0aW9uIApsaWJyYXJ5KFNDSVNTT1JTKSAgICAjIG91ciBwYWNrYWdlCmxpYnJhcnkobWl4dG9vbHMpICAgICMgR2F1c3NpYW4gbWl4dHVyZSBtb2RlbCBlc3RpbWF0aW9uCmxpYnJhcnkocGF0Y2h3b3JrKSAgICMgYWxpZ24gcGxvdHMKbGlicmFyeShsYXRleDJleHApICAgIyBMYVRlWApsaWJyYXJ5KHBhbGV0dGVlcikgICAjIGNvbG9yIHBhbGV0dGVzCmxpYnJhcnkoQ09OSUNTbWF0KSAgICMgQ05WIGVzdGltYXRpb24KbGlicmFyeShyZXRpY3VsYXRlKSAgIyBQeXRob24gaW50ZXJmYWNlCmxpYnJhcnkoa2FibGVFeHRyYSkgICMgcHJldHR5IHRhYmxlcwpsaWJyYXJ5KHdlc2FuZGVyc29uKSAjIG1vcmUgY29sb3IgcGFsZXR0ZXMKYGBgCgojIyBQeXRob24KCmBgYHtweXRob259CmltcG9ydCBudW1weSBhcyBucApmcm9tIG9wZW5UU05FIGltcG9ydCBUU05FRW1iZWRkaW5nCmZyb20gb3BlblRTTkUgaW1wb3J0IGluaXRpYWxpemF0aW9uCmZyb20gb3BlblRTTkUuYWZmaW5pdHkgaW1wb3J0IE11bHRpc2NhbGUKZnJvbSBvcGVuVFNORS5hZmZpbml0eSBpbXBvcnQgUGVycGxleGl0eUJhc2VkTk4KYGBgCgojIERhdGEKCkZpcnN0IHdlIGxvYWQgaW4gdGhlICRcdGV4dHtnZW5lfSBcdGltZXMgXHRleHR7Y2VsbH0kIGNvdW50cyBtYXRyaXgsIHRoZW4gY3JlYXRlIGEgYFNldXJhdGAgb2JqZWN0IHRvIGhvbGQgaXQgaW4uIE5leHQsIHdlIGFkZCBzYW1wbGVuYW1lLCB0aXNzdWUgdHlwZSwgYW5kIHBhdGllbnQgc2V4IG1ldGFkYXRhIHRha2VuIGZyb20gdGhlIHB1YmxpY2x5IGF2YWlsYWJsZSBkYXRhc2V0LgoKYGBge3J9CnJhd19jb3VudHMgPC0gUmVhZDEwWChkYXRhLmRpciA9ICJ+L0Rlc2t0b3AvRGF0YS9FbHlhZGEgUmF3L0FsbCBIdW1hbi8iKQpwZGFjIDwtIENyZWF0ZVNldXJhdE9iamVjdChyYXdfY291bnRzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvamVjdCA9ICJFbHlhZGEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluLmNlbGxzID0gMywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbi5mZWF0dXJlcyA9IDUwMCkKcGRhY0BtZXRhLmRhdGEkc2FtcGxlIDwtIGNhc2Vfd2hlbihncmVwbCgiLTEiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gIlNSUjkyNzQ1MzYiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTIiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gIlNSUjkyNzQ1MzciLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTMiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gIlNSUjkyNzQ1MzgiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTQiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gIlNSUjkyNzQ1MzkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItNSIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiU1JSOTI3NDU0MCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItNiIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiU1JSOTI3NDU0MSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItNyIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiU1JSOTI3NDU0MiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItOCIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiU1JSOTI3NDU0MyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItOSIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiU1JSOTI3NDU0NCIpCnBkYWNAbWV0YS5kYXRhJGNvbmRpdGlvbiA8LSBjYXNlX3doZW4oZ3JlcGwoIi0xIiwgcm93bmFtZXMocGRhY0BtZXRhLmRhdGEpKSB+ICJQREFDIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIi0yIiwgcm93bmFtZXMocGRhY0BtZXRhLmRhdGEpKSB+ICJQREFDIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIi0zIiwgcm93bmFtZXMocGRhY0BtZXRhLmRhdGEpKSB+ICJQREFDIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIi00Iiwgcm93bmFtZXMocGRhY0BtZXRhLmRhdGEpKSB+ICJQREFDIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIi01Iiwgcm93bmFtZXMocGRhY0BtZXRhLmRhdGEpKSB+ICJQREFDIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIi02Iiwgcm93bmFtZXMocGRhY0BtZXRhLmRhdGEpKSB+ICJBZGpOb3JtIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIi03Iiwgcm93bmFtZXMocGRhY0BtZXRhLmRhdGEpKSB+ICJQREFDIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIi04Iiwgcm93bmFtZXMocGRhY0BtZXRhLmRhdGEpKSB+ICJBZGpOb3JtIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIi05Iiwgcm93bmFtZXMocGRhY0BtZXRhLmRhdGEpKSB+ICJQREFDIikKcGRhY0BtZXRhLmRhdGEkc2V4IDwtIGNhc2Vfd2hlbihncmVwbCgiLTEiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gImZlbWFsZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItMiIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAibWFsZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItMyIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAibWFsZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItNCIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAibWFsZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItNSIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAibWFsZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCItNiIsIHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSkgfiAiZmVtYWxlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIi03Iiwgcm93bmFtZXMocGRhY0BtZXRhLmRhdGEpKSB+ICJmZW1hbGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTgiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gIm1hbGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiLTkiLCByb3duYW1lcyhwZGFjQG1ldGEuZGF0YSkpIH4gImZlbWFsZSIpCmBgYAoKYGBge3IsIGVjaG89RkFMU0V9CnJtKHJhd19jb3VudHMpCmBgYAoKIyBQcmVwcm9jZXNzaW5nCgpXZSBydW4gdGhlIHR5cGljYWwgc2luZ2xlIGNlbGwgcHJlLXByb2Nlc3Npbmcgc3RlcHMgb24gb3VyIGNlbGxzIC0gbm9ybWFsaXphdGlvbiwgZGltZW5zaW9uIHJlZHVjdGlvbiwgYW5kIGNsdXN0ZXJpbmcuIAoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CnBkYWMgPC0gUHJlcGFyZURhdGEoc2V1cmF0Lm9iamVjdCA9IHBkYWMsIAogICAgICAgICAgICAgICAgICAgIG4uSFZHID0gNDAwMCwgCiAgICAgICAgICAgICAgICAgICAgbi5QQyA9IDIwLCAKICAgICAgICAgICAgICAgICAgICByZWdyZXNzLm10ID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgIHJlZ3Jlc3MuY2MgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgd2hpY2guZGltLnJlZHVjID0gInRzbmUiLCAKICAgICAgICAgICAgICAgICAgICBpbml0aWFsLnJlc29sdXRpb24gPSAwLjQsIAogICAgICAgICAgICAgICAgICAgIHJhbmRvbS5zZWVkID0gNjI5KQpgYGAKCkxldCdzIGNoZWNrIG91dCB0aGUgdC1TTkUgZW1iZWRkaW5nLiBJdCBsb29rcyBkZWNlbnQsIGJ1dCBjb3VsZCBkZWZpbml0ZWx5IGJlIGltcHJvdmVkLiBHbG9iYWxseSwgdGhlIGNsdXN0ZXJzIGFyZSBhcnJhbmdlZCBpbiBhIGJsb2IgLSB3aGljaCBpc24ndCB2ZXJ5IGluZm9ybWF0aXZlIC0gdGhvdWdoIHRoZSBsb2NhbCBzdHJ1Y3R1cmUgc2VlbXMgdG8gaGF2ZSBiZWVuIHByZXNlcnZlZCBmYWlybHkgd2VsbC4gVmlzdWFsbHksIHRoZXJlIGFyZSBzZXZlcmFsIGNsdXN0ZXJzIHRoYXQgY29udGFpbiBzdWJncm91cHMgLSBjbHVzdGVycyAzLCA0LCA1LCA2LCAmIDkgbG9vayBsaWtlIGdvb2QgY2FuZGlkYXRlcyBmb3IgcmVjbHVzdGVyaW5nLiAKCmBgYHtyfQpwMGEgPC0gRGltUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidHNuZSIsIHB0LnNpemUgPSAwLjc1KSArIAogICAgICAgc2NhbGVfY29sb3JfcGFsZXR0ZWVyX2QoImdndGhlbWVzOjpDbGFzc2ljXzIwIikgKyAKICAgICAgIGxhYnMoeCA9ICJ0LVNORSAxIiwgeSA9ICJ0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArIAogICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSA0KSkpCnAwYQpgYGAKCldlIGNvbXB1dGUgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgc2lsaG91ZXR0ZSBzY29yZXMgZm9yIGVhY2ggY2x1c3Rlci4gCgpgYGB7cn0Kc2lsX2RmIDwtIENvbXB1dGVTaWxob3VldHRlU2NvcmVzKHBkYWMsIGF2ZyA9IEZBTFNFKQpwMGIgPC0gZ2dwbG90KHNpbF9kZiwgYWVzKHggPSBDbHVzdGVyLCB5ID0gU2NvcmUsIGZpbGwgPSBDbHVzdGVyKSkgKyAKICAgICAgIGdlb21fdmlvbGluKGRyYXdfcXVhbnRpbGVzID0gLjUsIGNvbG9yID0gImJsYWNrIiwgc2NhbGUgPSAid2lkdGgiKSArIAogICAgICAgc2NhbGVfZmlsbF9wYWxldHRlZXJfZCgiZ2d0aGVtZXM6OkNsYXNzaWNfMjAiKSArIAogICAgICAgbGFicyh5ID0gIlNpbGhvdWV0dGUgU2NvcmUiLCBmaWxsID0gIkxvdXZhaW5cbkNsdXN0ZXJzIikgKyAKICAgICAgIHRoZW1lX21pbmltYWwoKSArIAogICAgICAgdGhlbWUocGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BLCBzaXplID0gMSksIAogICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwgCiAgICAgICAgICAgICBsZWdlbmQuZGlyZWN0aW9uID0gInZlcnRpY2FsIiwgCiAgICAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMiksIAogICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwgCiAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIyKSwgCiAgICAgICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwgCiAgICAgICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKCksIAogICAgICAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gIml0YWxpYyIsIHNpemUgPSAxMCkpCmBgYAoKTG9va2luZyBhdCB0aGUgc2lsaG91ZXR0ZSBzY29yZSBkaXN0cmlidXRpb24gZm9yIGVhY2ggY2x1c3Rlciwgd2Ugc2VlIHRoYXQgQ2x1c3RlciAxMCBzZWVtcyB0byBoYXZlIHRoZSBiZXN0IGZpdCwgYW5kIENsdXN0ZXJzIDEsIDIsICYgOSBzZWVtIHRvIGhhdmUgcHJldHR5IHBvb3IgZml0cy4gCgpgYGB7cn0KcDBiCmBgYAoKTGFzdGx5IHdlJ2xsIGlkZW50aWZ5IG1hcmtlciBnZW5lcyBmb3IgZWFjaCBvZiB0aGUgY2x1c3RlcnMuIAoKYGBge3J9CnBkYWNfbWFya2VycyA8LSBGaW5kQWxsTWFya2VycyhwZGFjLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2ZjLnRocmVzaG9sZCA9IC41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3QudXNlID0gIndpbGNveCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25seS5wb3MgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbS5zZWVkID0gNjI5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2UgPSBGQUxTRSkgJT4lIAogICAgICAgICAgICAgICAgZmlsdGVyKHBfdmFsX2FkaiA8IC4wNSkgJT4lIAogICAgICAgICAgICAgICAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIAogICAgICAgICAgICAgICAgYXJyYW5nZShkZXNjKGF2Z19sb2cyRkMpKSAlPiUgCiAgICAgICAgICAgICAgICBzbGljZV9oZWFkKG4gPSA1KQpwMGMgPC0gRG90UGxvdChwZGFjLCBmZWF0dXJlcyA9IHVuaXF1ZShwZGFjX21hcmtlcnMkZ2VuZSksIGRvdC5zY2FsZSA9IDEwKSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHBhbGV0dGVlcl9kKCJ3ZXNhbmRlcnNvbjo6Wmlzc291MSIpKSArCiAgICAgICBsYWJzKGNvbG9yID0gIkV4cHJlc3Npb24iLCBzaXplID0gIiUgRXhwcmVzc2VkIiwgeSA9ICJMb3V2YWluIENsdXN0ZXIiKSArIAogICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgc2l6ZSA9IDEwLCB2anVzdCA9IDAuNSksIAogICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwgbGVnZW5kLmp1c3RpZmljYXRpb24gPSAiY2VudGVyIiwgCiAgICAgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BLCBzaXplID0gMSwgY29sb3IgPSAiYmxhY2siKSwgCiAgICAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksIAogICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLCAKICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCkpICsgCiAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9jb2xvcmJhcih0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhcmhlaWdodCA9IHVuaXQoMywgdW5pdHMgPSAiY20iKSwgdGl0bGUuaGp1c3QgPSAwLjUpLCAKICAgICAgICAgICAgICBzaXplID0gZ3VpZGVfbGVnZW5kKHRpdGxlLnBvc2l0aW9uID0gInRvcCIsIHRpdGxlLmhqdXN0ID0gMC41KSkKcDBjCmBgYAoKIyMgT3B0aW1pemUgRGltZW5zaW9uIFJlZHVjdGlvbgoKSSB0aGluayB0aGUgdHdvLWRpbWVuc2lvbmFsIHZpc3VhbGl6YXRpb24gb2YgdGhlIGNlbGxzIGNvdWxkIGJlIGltcHJvdmVkLiBXZSdsbCB0cnkgdXNpbmcgVU1BUCBhbmQgdGhlIEZhc3QgRm91cmllciBUcmFuc2Zvcm0tYWNjZWxlcmF0ZWQgRml0LVNORSAoYXMgaW1wbGVtZW50ZWQgaW4gdGhlIGBvcGVuVFNORWAgbGlicmFyeSkgdG8gaW1wcm92ZSB0aGUgZW1iZWRkaW5nLgoKIyMjIFVNQVAKCkl0IHNlZW1zIGxpa2UgVU1BUCBkb2VzIGEgZ29vZCBqb2Igb2YgY2xlYXJseSBzZXBhcmF0aW5nIG91ciBjbHVzdGVycyBhbmQgcHJlc2VydmluZyB0aGUgZ2xvYmFsIHN0cnVjdHVyZSBvZiB0aGUgZGF0YS4gSG93ZXZlciwgaXQncyBkaWZmaWN1bHQgdG8gc2VlIGxvY2FsIHN0cnVjdHVyZSB3aXRoaW4gc29tZSBvZiB0aGUgY2x1c3RlcnMgZHVlIHRvIHRoZWlyIGRlbnNpdHkuCgpgYGB7cn0KcGRhYyA8LSBSdW5VTUFQKHBkYWMsIAogICAgICAgICAgICAgICAgcmVkdWN0aW9uID0gInBjYSIsIAogICAgICAgICAgICAgICAgZGltcyA9IDE6MjAsIAogICAgICAgICAgICAgICAgdW1hcC5tZXRob2QgPSAidXdvdCIsIAogICAgICAgICAgICAgICAgbi5jb21wb25lbnRzID0gMiwgCiAgICAgICAgICAgICAgICBuLmVwb2NocyA9IDc1MCwgCiAgICAgICAgICAgICAgICBuLm5laWdoYm9ycyA9IDUwLCAKICAgICAgICAgICAgICAgIG1ldHJpYyA9ICJjb3NpbmUiLCAKICAgICAgICAgICAgICAgIHNlZWQudXNlID0gNjI5LCAKICAgICAgICAgICAgICAgIHZlcmJvc2UgPSBGQUxTRSkKcDEgPC0gRGltUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidW1hcCIsIHB0LnNpemUgPSAwLjc1KSArIAogICAgICBzY2FsZV9jb2xvcl9wYWxldHRlZXJfZCgiZ2d0aGVtZXM6OkNsYXNzaWNfMjAiKSArIAogICAgICBsYWJzKHggPSAiVU1BUCAxIiwgeSA9ICJVTUFQIDIiKSArIAogICAgICB0aGVtZV95ZWhsYWIoKSArCiAgICAgIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpICsgCiAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNCkpKQpwMQpgYGAKCiMjIyBGaXQtU05FCgpGb3IgaW5mb3JtYXRpb24gb24gaG93IHRvIGluc3RhbGwgdGhlIGBvcGVuVFNORWAgaW1wbGVtZW50YXRpb24gb2YgRml0LVNORSBhbmQgaG93IHRvIHJ1biB0aGUgYWxnb3JpdGhtLCBwbGVhc2UgdmlzaXQgW3RoZSBleGNlbGxlbnQgR2l0SHViIHJlcG9zaXRvcnkgb2YgUGF2bGluIFBvbGljYXJdKGh0dHBzOi8vZ2l0aHViLmNvbS9wYXZsaW4tcG9saWNhci9vcGVuVFNORSkuCgpGaXJzdCB3ZSdsbCBydW4gYSBzaW1wbGUsIHN0YW5kYXJkIEZpdC1TTkUgZW1iZWRkaW5nLiBJdCdzIG5lY2Vzc2FyeSB0byBtYWtlIHRoZSBQQ0EgZW1iZWRkaW5ncyBhY2Nlc3NpYmxlIGJ5IFB5dGhvbi4KCmBgYHtyfQpwY19kZiA8LSBFbWJlZGRpbmdzKHBkYWMsIHJlZHVjdGlvbiA9ICJwY2EiKQpgYGAKCmBgYHtweXRob259CiMgaW1wb3J0IGRhdGEKcGNfZGYgPSBucC5hcnJheShyLnBjX2RmKQojIHJ1biBGaXQtU05FCmFmZmluID0gUGVycGxleGl0eUJhc2VkTk4ocGNfZGYsIHBlcnBsZXhpdHk9MzAsIG1ldHJpYz0nY29zaW5lJywgcmFuZG9tX3N0YXRlPTYyOSkKaW5pdCA9IGluaXRpYWxpemF0aW9uLnBjYShwY19kZiwgcmFuZG9tX3N0YXRlPTYyOSkKdHNuZTEgPSBUU05FRW1iZWRkaW5nKGluaXQsIGFmZmluLCBuZWdhdGl2ZV9ncmFkaWVudF9tZXRob2Q9J2ZmdCcpCmVtYmVkMSA9IHRzbmUxLm9wdGltaXplKG5faXRlcj0zNTAsIGV4YWdnZXJhdGlvbj0xMiwgbW9tZW50dW09MC42KSAKZW1iZWQyID0gZW1iZWQxLm9wdGltaXplKG5faXRlcj03NTAsIG1vbWVudHVtPTAuOCkKYGBgCgpUaGUgZW1iZWRkaW5nIGxvb2tzIGdvb2QsIHNvIHdlJ2xsIHVzZSBpdCBnb2luZyBmb3J3YXJkcy4KCmBgYHtyfQplbWJlZCA8LSBhcy5tYXRyaXgocHkkZW1iZWQyKQpyb3duYW1lcyhlbWJlZCkgPC0gY29sbmFtZXMocGRhYykKcGRhY0ByZWR1Y3Rpb25zJGZpdHNuZSA8LSBDcmVhdGVEaW1SZWR1Y09iamVjdChlbWJlZGRpbmdzID0gZW1iZWQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleSA9ICJGaXRTTkVfIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzYXkgPSAiU0NUIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2xvYmFsID0gVFJVRSkKcDIgPC0gRGltUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAiZml0c25lIiwgcHQuc2l6ZSA9IDAuNzUpICsgCiAgICAgIHNjYWxlX2NvbG9yX3BhbGV0dGVlcl9kKCJnZ3RoZW1lczo6Q2xhc3NpY18yMCIpICsgCiAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgIHRoZW1lX3llaGxhYigpICsKICAgICAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkgKyAKICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSA0KSkpCnAyCmBgYAoKRHVlIHRvIHRoZSB3YXkgYFNldXJhdGAgYWNjZXNzZXMgY2VsbCBlbWJlZGRpbmdzLCB3ZSdsbCBuZWVkIHRvIHJlcGxhY2Ugb3VyIG9yaWdpbmFsIHQtU05FIGRpbWVuc2lvbiByZWR1Y3Rpb24gaW4gb3VyIGBTZXVyYXRgIG9iamVjdCB3aXRoIHRoZSBuZXcgRml0LVNORSB2ZXJzaW9uLiBXZSdsbCBrZWVwIHRoZSBvcmlnaW5hbCBCYXJuZXMtSHV0IHQtU05FIGVtYmVkZGluZyB1bmRlciBhIHNlcGFyYXRlIG5hbWUuCgpgYGB7cn0KcGRhY0ByZWR1Y3Rpb25zJGJoX3RzbmUgPC0gcGRhY0ByZWR1Y3Rpb25zJHRzbmUKcGRhY0ByZWR1Y3Rpb25zJHRzbmUgPC0gcGRhY0ByZWR1Y3Rpb25zJGZpdHNuZQpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30Kcm0oZW1iZWQsIHBjX2RmKQpnYyh2ZXJib3NlID0gRkFMU0UpCmBgYAoKIyBTaW5nbGVSIENlbGwgVHlwZSBJZGVudGlmaWNhdGlvbgoKIyMgU2luZ2xlIENlbGwgUk5BLXNlcSBSZWZlcmVuY2UgRGF0YQoKSGVyZSB3ZSB1c2UgdGhlIGBTaW5nbGVSYCBwYWNrYWdlIHRvIGlkZW50aWZ5IGJyb2FkIGNlbGwgdHlwZXMuIFRoZSByZWZlcmVuY2UgZGF0YXNldCB3ZSBsb2FkIGlzIGFuIGBzY3RyYW5zZm9ybWAtbm9ybWFsaXplZCB2ZXJzaW9uIG9mIHRoZSByYXcgY291bnRzIGF2YWlsYWJsZSBpbiBgc2NSTkFzZXE6OkJhcm9uUGFuY3JlYXNEYXRhKClgLCB3aGljaCBjb25zaXN0cyBvZiBub3JtYWwgcGFuY3JlYXMgY2VsbHMgdGhhdCB3ZXJlIHNlcXVlbmNlZCBhbmQgYW5ub3RhdGVkIGJ5IHRoZSByZXNlYXJjaGVycy4KCmBgYHtyfQpzY19yZWYgPC0gcmVhZFJEUygiL1ZvbHVtZXMvbGFicy9Ib21lL0plbiBKZW4gWWVoIExhYi9KYWNrL3NjUk5Bc2VxL1NldXJhdC9zaW5nbGVfY2VsbF9yZWZfbm9ybWFsaXplZC5SZHMiKQpzY19wcmVkcyA8LSBTaW5nbGVSKHRlc3QgPSBkYXRhLmZyYW1lKHBkYWNAYXNzYXlzJFNDVEBkYXRhKSwgCiAgICAgICAgICAgICAgICAgICAgcmVmID0gc2NfcmVmLCAKICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzY19yZWYkbGFiZWwsIAogICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJjbHVzdGVyIiwgCiAgICAgICAgICAgICAgICAgICAgY2x1c3RlcnMgPSBwZGFjJHNldXJhdF9jbHVzdGVycywgCiAgICAgICAgICAgICAgICAgICAgZGUubWV0aG9kID0gIndpbGNveCIpCnBkYWNbWyJTaW5nbGVSLmxhYmVscy5zYyJdXSA8LSBzY19wcmVkcyRsYWJlbHNbbWF0Y2gocGRhY1tbXV1bWyJzZXVyYXRfY2x1c3RlcnMiXV0sIHJvd25hbWVzKHNjX3ByZWRzKSldCnBkYWMkU2luZ2xlUi5sYWJlbHMuc2MgPC0gY2FzZV93aGVuKHBkYWMkU2luZ2xlUi5sYWJlbHMuc2MgPT0gImFjaW5hciIgfiAiQWNpbmFyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBkYWMkU2luZ2xlUi5sYWJlbHMuc2MgPT0gImFjdGl2YXRlZF9zdGVsbGF0ZSIgfiAiQWN0aXZhdGVkIFN0ZWxsYXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGRhYyRTaW5nbGVSLmxhYmVscy5zYyA9PSAiZHVjdGFsIiB+ICJEdWN0YWwiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGRhYyRTaW5nbGVSLmxhYmVscy5zYyA9PSAibWFjcm9waGFnZSIgfiAiTWFjcm9waGFnZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBkYWMkU2luZ2xlUi5sYWJlbHMuc2MgPT0gInRfY2VsbCIgfiAiVCIpCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHRoZXJlJ3MgYSBsYXJnZSBpbW11bmUgcG9wdWxhdGlvbiwgYXMgd2VsbCBhcyBzbWFsbGVyIGR1Y3RhbCwgZmlicm9ibGFzdCAoZGVub3RlZCBhY3RpdmF0ZWQgc3RlbGxhdGUgaW4gdGhlIHJlZmVyZW5jZSBkYXRhc2V0KSwgYW5kIGFjaW5hciBncm91cHMuIFRoZXNlIGJyb2FkIGNlbGwgdHlwZXMgbGluZSB1cCB3aXRoIHdoYXQgd2UgZXhwZWN0ZWQgdG8gc2VlIGdpdmVuIHRoZSBhdXRob3JzJyBvcmlnaW5hbCBjZWxsIGNsdXN0ZXIgYW5ub3RhdGlvbnMuIAoKYGBge3J9CnAzIDwtIERpbVBsb3QocGRhYywgcmVkdWN0aW9uID0gInRzbmUiLCBncm91cC5ieSA9ICJTaW5nbGVSLmxhYmVscy5zYyIsIHB0LnNpemUgPSAwLjc1KSArIAogICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoImdnc2NpOjpkZWZhdWx0X25lam0iKSkgKyAKICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAyLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSA0KSkpCnAzCmBgYAoKIyMgQnVsayBUaXNzdWUgUk5BLXNlcSBSZWZlcmVuY2UgRGF0YQoKVGhpcyBkYXRhc2V0IGlzIGNvbXBvc2VkIG9mIGxhYmVsZWQgJiBsb2ctbm9ybWFsaXplZCBidWxrIFJOQS1zZXEgc2FtcGxlcyBmcm9tIHRoZSBIdW1hbiBQcmltYXJ5IENlbGwgQXRsYXMuCgpgYGB7cn0KYnVsa19yZWYgPC0gSHVtYW5QcmltYXJ5Q2VsbEF0bGFzRGF0YSgpCmJ1bGtfcHJlZHMgPC0gU2luZ2xlUih0ZXN0ID0gZGF0YS5mcmFtZShwZGFjQGFzc2F5cyRTQ1RAZGF0YSksIAogICAgICAgICAgICAgICAgICAgICAgcmVmID0gYnVsa19yZWYsIAogICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYnVsa19yZWYkbGFiZWwubWFpbiwgCiAgICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAiY2x1c3RlciIsIAogICAgICAgICAgICAgICAgICAgICAgY2x1c3RlcnMgPSBwZGFjJHNldXJhdF9jbHVzdGVycywgCiAgICAgICAgICAgICAgICAgICAgICBkZS5tZXRob2QgPSAid2lsY294IikKcGRhY1tbIlNpbmdsZVIubGFiZWxzLmJ1bGsiXV0gPC0gYnVsa19wcmVkcyRsYWJlbHNbbWF0Y2gocGRhY1tbXV1bWyJzZXVyYXRfY2x1c3RlcnMiXV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lcyhidWxrX3ByZWRzKSldCnBkYWMkU2luZ2xlUi5sYWJlbHMuYnVsayA8LSBjYXNlX3doZW4ocGRhYyRTaW5nbGVSLmxhYmVscy5idWxrID09ICJCX2NlbGwiIH4gIkIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZGFjJFNpbmdsZVIubGFiZWxzLmJ1bGsgPT0gIkVwaXRoZWxpYWxfY2VsbHMiIH4gIkVwaXRoZWxpYWwiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZGFjJFNpbmdsZVIubGFiZWxzLmJ1bGsgPT0gIkJfY2VsbC0iIH4gIkIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZGFjJFNpbmdsZVIubGFiZWxzLmJ1bGsgPT0gIlRfY2VsbHMiIH4gIlQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBwZGFjJFNpbmdsZVIubGFiZWxzLmJ1bGspCmBgYAoKVGhlIGJ1bGsgcmVmZXJlbmNlIGdpdmVzIHVzIHNvbWV3aGF0IG1vcmUgZ3JhbnVsYXIgbGFiZWxzIGZvciB0aGUgaW1tdW5lIGNlbGxzLCBhbmQgY29uZmlybXMgdGhlIGlkZW50aXRpZXMgb2YgdGhlIGR1Y3RhbCAvIGVwaXRoZWxpYWwgYW5kIHN0cm9tYSBjbHVzdGVycy4gCgpgYGB7cn0KcDQgPC0gRGltUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidHNuZSIsIGdyb3VwLmJ5ID0gIlNpbmdsZVIubGFiZWxzLmJ1bGsiLCBwdC5zaXplID0gMC43NSkgKyAKICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJnZ3NjaTo6ZGVmYXVsdF9uZWptIikpICsgCiAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMiwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNCkpKQpwNApgYGAKCmBgYHtyLCBlY2hvPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30Kcm0oc2NfcHJlZHMsIGJ1bGtfcHJlZHMsIGJ1bGtfcmVmLCBzY19yZWYpCmdjKHZlcmJvc2UgPSBGQUxTRSkKYGBgCgpPbmUgc2hvdWxkbid0IHVzZSBgU2luZ2xlUmAgYXMgdGhlIGZpbmFsIGF1dGhvcml0eSBmb3IgY2VsbCB0eXBlcywgYnV0IHdlIHdlcmUgYWJsZSB0byBjb25maXJtIHRoZSBpZGVudGl0aWVzIG9mIHRoZSBkdWN0YWwgYW5kIGZpYnJvYmxhc3QgY2x1c3RlcnMsIHdoaWNoIGlzIGltcG9ydGFudCBmb3IgdGhpcyBkYXRhc2V0IGFzIHRoZSBjZWxscyB3ZSBhcmUgbW9zdCBpbnRlcmVzdGVkIGluIGFyZSB0aGUgY2FuY2VyLWFzc29jaWF0ZWQgZmlicm9ibGFzdHMgKENBRnMpLiAKCiMgQ09OSUNTbWF0IENOViBFc3RpbWF0aW9uCgpOZXh0IHdlJ2xsIGF0dGVtcHQgdG8gaWRlbnRpZnkgbWFsaWduYW50IGNlbGxzIHVzaW5nIHNpbmdsZS1jZWxsIGNvcHkgbnVtYmVyIHZhcmlhdGlvbiBlc3RpbWF0aW9uIGFzIGltcGxlbWVudGVkIGluIHRoZSBgQ09OQ0lTbWF0YCBwYWNrYWdlLiBEZXRhaWxzIG9mIHRoZSBHTU0gbWV0aG9kb2xvZ3kgdXNlZCBjYW4gYmUgZm91bmQgYXQgW3RoZSBEaWF6IExhYidzIEdpdEh1YiByZXBvc2l0b3J5XShodHRwczovL2dpdGh1Yi5jb20vZGlhemxhYi9DT05JQ1MpLiBOb3RlOiB0aGlzIHN0ZXAgaXMgbWVtb3J5LWludGVuc2l2ZSBiZWNhdXNlIDEpIGl0IHJlcXVpcmVzIHRoZSBzcGFyc2UgY291bnRzIG1hdHJpeCB0byBiZSBjYXN0IHRvIGEgZGVuc2UgbWF0cml4IGFuZCAyKSBhIGxvdCBvZiBHYXVzc2lhbiBtaXh0dXJlIG1vZGVscyBnZXQgZXN0aW1hdGVkLiBJZiB5b3VyIG1hY2hpbmUgZG9lc24ndCBoYXZlIGEgbG90IG9mIFJBTSBpdCBtaWdodCBiZSBiZXN0IHRvIHNraXAgdGhpcyBhbmQgbWFudWFsbHkgYW5ub3RhdGUgdGhlIG1hbGlnbmFudCBjZWxscyBpbnN0ZWFkIHRocm91Z2ggdGhlIHVzYWdlIG9mIGNhbm9uaWNhbCBtYXJrZXJzIG9yIHRoZSBgVkFNYCBzaW5nbGUtY2VsbCBHU0VBIG1ldGhvZG9sb2d5LiAKCmBgYHtyLCByZXN1bHRzPSJoaWRlIn0KY2hyb21fcmVnaW9ucyA8LSByZWFkLnRhYmxlKCIvVm9sdW1lcy9sYWJzL0hvbWUvSmVuIEplbiBZZWggTGFiL0phY2svc2NSTkFzZXEvY2hyb21fYXJtX3Bvc2l0aW9ucy50eHQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICJcdCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBUUlVFKQpnZW5lX3BvcyA8LSBnZXRHZW5lUG9zaXRpb25zKHJvd25hbWVzKHBkYWMpKQpjcG0gPC0gdCh0KGFzLm1hdHJpeChwZGFjQGFzc2F5cyRTQ1RAY291bnRzKSkgLyBjb2xTdW1zKGFzLm1hdHJpeChwZGFjQGFzc2F5cyRTQ1RAY291bnRzKSkpICogMTBeNQpjcG0gPC0gbG9nMihjcG0gKyAxKQpub3JtX2ZhY3RvciA8LSBjYWxjTm9ybUZhY3RvcnMoY3BtKQpjbnZfZXN0IDwtIHBsb3RBbGwobWF0ID0gY3BtLCAKICAgICAgICAgICAgICAgICAgIG5vcm1GYWN0b3IgPSBub3JtX2ZhY3RvciwgCiAgICAgICAgICAgICAgICAgICByZWdpb25zID0gY2hyb21fcmVnaW9ucywgCiAgICAgICAgICAgICAgICAgICBnZW5lX3BvcyA9IGdlbmVfcG9zLCAKICAgICAgICAgICAgICAgICAgIGZuYW1lID0gIkVseWFkYSIpCmBgYAoKYGBge3IsIGVjaG89RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQpnYyh2ZXJib3NlID0gRkFMU0UpCmBgYAoKCiMjIFZpc3VhbGl6aW5nIENOVnMKCkFmdGVyIGVzdGltYXRpbmcgQ05Wcywgd2UgY2x1c3RlciB0aGUgY2VsbHMgaW50byAkayA9IDMkIGNsdXN0ZXJzLCB3aXRoIHRoZSBob3BlIG9mIGZpbmRpbmcgb25lIGxhcmdlIGNsdXN0ZXIgb2Ygbm9ybWFsIGNlbGxzIGFuZCB0d28gc21hbGxlciBjbHVzdGVycyBjb21wb3NlZCBvZiBDQUZzIGFuZCBQREFDIGNlbGxzLiAKCmBgYHtyfQpiaWNfdGFibGUgPC0gcmVhZC50YWJsZSgiLi9FbHlhZGFfQklDX0xSLnR4dCIsIAogICAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiXHQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICBjaGVjay5uYW1lcyA9IEZBTFNFKQpjYW5kX3JlZ2lvbnMgPC0gcm93bmFtZXMoYmljX3RhYmxlW2JpY190YWJsZSRgQklDIGRpZmZlcmVuY2VgID4gMTAwMCAmIGJpY190YWJsZSRgTFJUIGFkai4gcC12YWxgIDwgLjAxLCBdKQpoaXN0MSA8LSBwbG90SGlzdG9ncmFtKGNudl9lc3RbLCBjYW5kX3JlZ2lvbnNdLCAKICAgICAgICAgICAgICAgICAgICAgICBjcG0sIAogICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJzID0gMywgCiAgICAgICAgICAgICAgICAgICAgICAgenNjb3JlVGhyZXNob2xkID0gMywgCiAgICAgICAgICAgICAgICAgICAgICAgY2VsbHR5cGVzID0gcGRhYyRTaW5nbGVSLmxhYmVscy5idWxrLCAKICAgICAgICAgICAgICAgICAgICAgICBwYXRpZW50cyA9IHBkYWMkc2FtcGxlKQpgYGAKCldlIGFkZCB0aGUgbm9ybWFsIHZzLiBtYWxpZ25hbnQgY2VsbCBsYWJlbHMgaW4gdG8gb3VyIGBTZXVyYXRgIG9iamVjdCdzIG1ldGFkYXRhLCB0aGVuIHZpc3VhbGl6ZSB0aGUgcmVzdWx0cy4gQXMgZXhwZWN0ZWQsIHRoZSBtYWxpZ25hbnQgY2VsbHMgYXJlIGxvY2F0ZWQgaW4gdGhlIGNsdXN0ZXJzIGlkZW50aWZpZWQgYnkgYFNpbmdsZVJgIGFzIGR1Y3RhbCBjZWxscyBhbmQgZmlicm9ibGFzdHMuIFRoaXMgaW5kaWNhdGVzIHRoYXQgYENPTklDU21hdGAgZGlkIGEgc29saWQgam9iIG9mIGVzdGltYXRpbmcgdGhlIENOVnMgLSBubyBlYXN5IGZlYXQgd2l0aCBzcGFyc2UsIG5vaXN5IHNpbmdsZS1jZWxsIGRhdGEuIAoKYGBge3J9Cm5vcm1hbCA8LSB3aGljaChoaXN0MSA9PSAxKQptYWxpZ25hbnQgPC0gd2hpY2goaGlzdDEgIT0gMSkKcGRhY0BtZXRhLmRhdGEkbWFsaWcgPC0gaWZlbHNlKHJvd25hbWVzKHBkYWNAbWV0YS5kYXRhKSAlaW4lIG5hbWVzKG5vcm1hbCksICJOb3JtYWwiLCAiTWFsaWduYW50IikKcDUgPC0gRGltUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidHNuZSIsIGdyb3VwLmJ5ID0gIm1hbGlnIiwgcHQuc2l6ZSA9IDAuNzUpICsgCiAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiWmlzc291MSIsIG4gPSA1KVtjKDUsIDIpXSkgKyAKICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSA0KSkpCnA1CmBgYAoKYGBge3IsIGVjaG89RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQpybShjcG0sIGJpY190YWJsZSwgY2hyb21fcmVnaW9ucywgY252X2VzdCwgZ2VuZV9wb3MsIGNhbmRfcmVnaW9ucywgaGlzdDEsIG5vcm1hbCwgbm9ybV9mYWN0b3IsIG1hbGlnbmFudCkKZ2ModmVyYm9zZSA9IEZBTFNFKSAgIyBub3QgcmVjb21tZW5kZWQsIGJ1dCBpdCBjb3VsZCBoZWxwIHRoaXMgZG9jdW1lbnQgY29tcGlsZSwgc28gLi4uCmBgYAoKIyBERUNPREVSCgpOZXh0LCB3ZSB1c2UgW0RyLiBYaWFubHUgUGVuZydzIERFQ09ERVJdKGh0dHBzOi8vZ2l0aHViLmNvbS9sYXVyYXBlbmcvZGVjb2RlcnIpIGluIG9yZGVyIHRvIGRlY29udm9sdmUgdGhlIGRhdGFzZXQgYW5kIGFzc2lnbiB3ZWlnaHRzIHRvIGVhY2ggY2VsbCB1c2luZyBub24tbmVnYXRpdmUgbWF0cml4IGZhY3Rvcml6YXRpb24uIFdlIGNhbGN1bGF0ZSBiYXNhbCAmIGNsYXNzaWNhbCBQREFDLCBub3JtYWwgJiBhY3RpdmF0ZWQgc3Ryb21hLCBpbW11bmUsIGFuZCBlbmRvY3JpbmUgJiBleG9jcmluZSBwYW5jcmVhcyBjb21wYXJ0bWVudCB3ZWlnaHRzLgoKYGBge3J9CnNhbXBsZV93dHNfdW5zY2FsZWQgPC0gRGVjb25fc2luZ2xlX3NhbXBsZSgiVENHQV9STkFzZXFfUEFBRCIsIHBkYWNAYXNzYXlzJFNDVEBkYXRhLCAiZ2VuZVN5bWJvbCIpCnNhbXBsZV93dHMgPC0gTm9ybV9QREFDX3dlaWdodHMoc2FtcGxlX3d0c191bnNjYWxlZCkKcGRhYyA8LSBBZGRNZXRhRGF0YShwZGFjLCBzYW1wbGVfd3RzJEltbXVuZSwgImltbXVuZSIpCnBkYWMgPC0gQWRkTWV0YURhdGEocGRhYywgc2FtcGxlX3d0cyRiY1JhdGlvLCAiYmNfcmF0aW8iKQpwZGFjIDwtIEFkZE1ldGFEYXRhKHBkYWMsIHNhbXBsZV93dHMkRXhvY3JpbmUsICJleG9jcmluZSIpCnBkYWMgPC0gQWRkTWV0YURhdGEocGRhYywgc2FtcGxlX3d0cyRFbmRvY3JpbmUsICJlbmRvY3JpbmUiKQpwZGFjIDwtIEFkZE1ldGFEYXRhKHBkYWMsIHNhbXBsZV93dHNfdW5zY2FsZWRbLCA5XSwgImJhc2FsIikKcGRhYyA8LSBBZGRNZXRhRGF0YShwZGFjLCBzYW1wbGVfd3RzX3Vuc2NhbGVkWywgNV0sICJjbGFzc2ljYWwiKQpwZGFjIDwtIEFkZE1ldGFEYXRhKHBkYWMsIHNhbXBsZV93dHMkTm9ybWFsU3Ryb21hLCAibm9ybV9zdHJvbWEiKQpwZGFjIDwtIEFkZE1ldGFEYXRhKHBkYWMsIHNhbXBsZV93dHMkQWN0aXZhdGVkU3Ryb21hLCAiYWN0X3N0cm9tYSIpCmBgYAoKIyMgVmlzdWFsaXppbmcgREVDT0RFUiBXZWlnaHRzCgojIyMgQmFzYWwgUERBQwoKVGhlIGJhc2FsIHdlaWdodHMgYXJlIGhpZ2hlc3QgaW4gYSBzdWJjbHVzdGVyIG9mIHRoZSBkdWN0YWwgZ3JvdXAgaWRlbnRpZmllZCB0aHJvdWdoIGBTaW5nbGVSYC4gVGhpcyBpcyBpbnRlcmVzdGluZyBhcyB0aGUgYXV0aG9ycyBkaWQgbm90IGZpbmQgZXZpZGVuY2Ugb2YgdGhlIGJhc2FsIHN1YnR5cGUgaW4gdGhlaXIgcGFwZXIuIAoKYGBge3J9CnA2IDwtIEZlYXR1cmVQbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiYmFzYWwiLCBwdC5zaXplID0gMC43NSkgKyAKICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICBOb0xlZ2VuZCgpCnA2CmBgYAoKIyMjIENsYXNzaWNhbCBQREFDCgpUaGUgY2xhc3NpY2FsIHdlaWdodHMgYXJlIGhpZ2hlc3QgaW4gYW5vdGhlciBzdWJjbHVzdGVyIG9mIHRoZSBkdWN0YWwgY2x1c3RlciwgYW5kIGNlbGxzIHdpdGggaGlnaCBjbGFzc2ljYWwgd2VpZ2h0cyBkbyBub3QgY29sbG9jYXRlIHdpdGggdGhvc2UgdGhhdCBoYXZlIGhpZ2ggYmFzYWwgd2VpZ2h0cy4gVGhlIHB1dGF0aXZlIGNsYXNzaWNhbCBhbmQgYmFzYWwgUERBQyBjZWxscyBhbHNvIGFsaWduIGNsb3NlbHkgd2l0aCB0aGUgY2VsbHMgaWRlbnRpZmllZCB0aHJvdWdoIGBDT05DSVNtYXRgIGFzIG1hbGlnbmFudC4gCgpgYGB7cn0KcDcgPC0gRmVhdHVyZVBsb3QocGRhYywgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJjbGFzc2ljYWwiLCBwdC5zaXplID0gMC43NSkgKyAKICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICBOb0xlZ2VuZCgpCnA3CmBgYAoKIyMjIEV4b2NyaW5lIFBhbmNyZWFzCgpUaGUgY2x1c3RlciBpZGVudGlmaWVkIHRocm91Z2ggYFNpbmdsZVJgIGFzIGFjaW5hciBjZWxscyBpcyB0aGUgb25seSBjbHVzdGVyIHdpdGggaGlnaCBleG9jcmluZSBwYW5jcmVhcyB3ZWlnaHRzLiAKCmBgYHtyfQpwOCA8LSBGZWF0dXJlUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gImV4b2NyaW5lIiwgcHQuc2l6ZSA9IDAuNzUpICsKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkKcDgKYGBgCgojIyMgRW5kb2NyaW5lIFBhbmNyZWFzCgpObyBjZWxscyBoYXZlIGhpZ2ggZW5kb2NyaW5lIHBhbmNyZWFzIHdlaWdodHMuIAoKYGBge3J9CnA5IDwtIEZlYXR1cmVQbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiZW5kb2NyaW5lIiwgcHQuc2l6ZSA9IDAuNzUpICsKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkKcDkKYGBgCgojIyMgSW1tdW5lCgpPbmNlIGFnYWluLCB3ZSBjb25maXJtIHRoZSBsYXJnZW5lc3Mgb2YgdGhlIGltbXVuZSBjZWxsIHBvcHVsYXRpb24gaW4gdGhpcyBkYXRhc2V0LiAKCmBgYHtyfQpwMTAgPC0gRmVhdHVyZVBsb3QocGRhYywgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJpbW11bmUiLCBwdC5zaXplID0gMC43NSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkKcDEwCmBgYAoKIyMjIE5vcm1hbCBTdHJvbWEKCkNlbGxzIHdpdGggaGlnaCBub3JtYWwgc3Ryb21hIHN0cm9tYSB3ZWlnaHRzIGFyZSBsb2NhdGVkIGluIHRoZSBjbHVzdGVyIGlkZW50aWZpZWQgYnkgYFNpbmdsZVJgIGFzIGJlaW5nIHN0cm9tYWwgY2VsbHMuIAoKYGBge3J9CnAxMSA8LSBGZWF0dXJlUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIm5vcm1fc3Ryb21hIiwgcHQuc2l6ZSA9IDAuNzUpICsKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkKcDExCmBgYAoKIyMjIEFjdGl2YXRlZCBTdHJvbWEKCkNlbGxzIHdpdGggaGlnaCBhY3RpdmF0ZWQgc3Ryb21hIHdlaWdodHMgYXJlIGFsc28gbG9jYXRlZCBpbiB0aGUgZmlicm9ibGFzdCBjbHVzdGVyLCBhbmQgZG8gbm90IGludGVyc2VjdCB3aXRoIHRoZSBjZWxscyB0aGF0IGhhdmUgaGlnaCBub3JtYWwgc3Ryb21hIHNjb3Jlcy4gVGhpcyBpbmRpY2F0ZXMgdGhhdCBgU0NJU1NPUlNgIHdpbGwgbW9zdCBsaWtlbHkgcGVyZm9ybSB3ZWxsIG9uIHRoZSBmaWJyb2JsYXN0IGNsdXN0ZXIgYW5kIGJlIGFibGUgdG8gcXVpY2tseSB0ZWFzZSBvdXQgdGhlIGNlbGwgc3VidHlwZXMuCgpgYGB7cn0KcDEyIDwtIEZlYXR1cmVQbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiYWN0X3N0cm9tYSIsIHB0LnNpemUgPSAwLjc1KSArCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpCnAxMgpgYGAKCiMgU0NJU1NPUlMKCk5vdyB0aGF0IHdlIGhhdmUgcm91Z2ggbGFiZWxzIGZyb20gYFNpbmdsZVJgLCBDTlZzIGZyb20gYENPTklDU21hdGAsIGFuZCBjb21wYXJ0bWVudCB3ZWlnaHRzIGZyb20gYERFQ09ERVJgLCB3ZSBzaG91bGQgaGF2ZSBtb3JlIHRoYW4gZW5vdWdoIGNlbGwtbGV2ZWwgbWV0YWRhdGEgdG8gbG9vayBmb3IgYW5kIGFubm90YXRlIGNlbGwgc3VidHlwZXMgdXNpbmcgYFNDSVNTT1JTYC4gCgojIyBGaWJyb2JsYXN0cwoKVGhlIGZpYnJvYmxhc3QgbWFya2VyIGdlbmVzIHByb3ZpZGVkIGJ5IEVseWFkYSAqZXQgYWwqIG1hdGNoIHRoZSBgU2luZ2xlUmAgcmVzdWx0cyBkZWZpbmluZyBjbHVzdGVyIDYgYXMgY29udGFpbmluZyBmaWJyb2JsYXN0cy4gCgpgYGB7cn0KcDEzIDwtIEZlYXR1cmVQbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ09MMUExIiwgcHQuc2l6ZSA9IDAuNzUpICsKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnModGl0bGUgPSAiQ09MMUExIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMTQgPC0gRmVhdHVyZVBsb3QocGRhYywgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDT0wzQTEiLCBwdC5zaXplID0gMC43NSkgKwogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh0aXRsZSA9ICJDT0wzQTEiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAxNSA8LSBGZWF0dXJlUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkxVTSIsIHB0LnNpemUgPSAwLjc1KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh0aXRsZSA9ICJMVU0iKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAxNiA8LSBGZWF0dXJlUGxvdChwZGFjLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkRDTiIsIHB0LnNpemUgPSAwLjc1KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh0aXRsZSA9ICJEQ04iKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwMTMgfCBwMTQpIC8gKHAxNSB8IHAxNikKYGBgCgojIyMgUmVjbHVzdGVyaW5nCgpIZXJlIHdlIHVzZSBgUmVjbHVzdGVyQ2VsbHMoKWAgdG8gaWRlbnRpZnkgc3ViY2x1c3RlcnMgd2l0aGluIGNsdXN0ZXIgNi4gV2UgZmluZCBmaXZlIGRpc3RpbmN0IHN1YmNsdXN0ZXJzLgoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CmZpYnJvIDwtIFJlY2x1c3RlckNlbGxzKHBkYWMsCiAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoLmNsdXN0ID0gNiwgCiAgICAgICAgICAgICAgICAgICAgICAgIG4uSFZHID0gNDAwMCwgCiAgICAgICAgICAgICAgICAgICAgICAgIG4uUEMgPSAyMCwgCiAgICAgICAgICAgICAgICAgICAgICAgIHJlc29sdXRpb24udmFscyA9IGMoLjAzLCAuMDUsIC4xKSwgCiAgICAgICAgICAgICAgICAgICAgICAgIGsudmFscyA9IGMoMjAsIDMwLCA0MCksIAogICAgICAgICAgICAgICAgICAgICAgICByZWRvLmVtYmVkZGluZyA9IFRSVUUpCmZpYnJvX3BjIDwtIEVtYmVkZGluZ3MoZmlicm8sICJwY2EiKQpgYGAKCldlJ2xsIGFnYWluIHJ1biBGaXQtU05FIG9uIHRoZSByZWNsdXN0ZXJlZCBjZWxscywgZm9yIGNvbnNpc3RlbmNpZXMgc2FrZS4gCgpgYGB7cHl0aG9ufQojIGltcG9ydCBkYXRhCmZpYnJvX3BjID0gci5maWJyb19wYwojIHJ1biBGaXQtU05FCmFmZmluX2ZpYnJvID0gUGVycGxleGl0eUJhc2VkTk4oZmlicm9fcGMsIHBlcnBsZXhpdHk9NDAsIG1ldHJpYz0nY29zaW5lJywgcmFuZG9tX3N0YXRlPTYyOSkKaW5pdCA9IGluaXRpYWxpemF0aW9uLnBjYShmaWJyb19wYywgcmFuZG9tX3N0YXRlPTYyOSkKdHNuZV9mID0gVFNORUVtYmVkZGluZyhpbml0LCBhZmZpbl9maWJybywgbmVnYXRpdmVfZ3JhZGllbnRfbWV0aG9kPSdmZnQnKQplbWJlZF9mMSA9IHRzbmVfZi5vcHRpbWl6ZShuX2l0ZXI9MjUwLCBleGFnZ2VyYXRpb249NSwgbW9tZW50dW09MC40KSAKZW1iZWRfZjIgPSBlbWJlZF9mMS5vcHRpbWl6ZShuX2l0ZXI9NzUwLCBleGFnZ2VyYXRpb249MSwgbW9tZW50dW09MC44KQpgYGAKClB1bGxpbmcgdGhlIHJlc3VsdHMgYmFjayBpbnRvIFIgYW5kIHZpc3VhbGl6aW5nIHRoZW0gc2hvd3MgY2xlYXIgc2VwYXJhdGlvbiBiZXR3ZWVuIHRoZSBzdWJjbHVzdGVycy4gVGhlcmUncyBzb21lIG5vaXNlIGluIHN1YmNsdXN0ZXIgMCwgYnV0IG90aGVyIHRoYW4gdGhhdCB0aGUgcmVlbWJlZGRpbmcgbG9va3Mgc29saWQuIAoKYGBge3J9CmVtYmVkX2ZpYnJvIDwtIGFzLm1hdHJpeChweSRlbWJlZF9mMikKcm93bmFtZXMoZW1iZWRfZmlicm8pIDwtIGNvbG5hbWVzKGZpYnJvKQpmaWJyb0ByZWR1Y3Rpb25zJGJoX3RzbmUgPC0gZmlicm9AcmVkdWN0aW9ucyR0c25lCmZpYnJvQHJlZHVjdGlvbnMkdHNuZTwtIENyZWF0ZURpbVJlZHVjT2JqZWN0KGVtYmVkZGluZ3MgPSBlbWJlZF9maWJybywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleSA9ICJGaXRTTkVfIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2F5ID0gIlNDVCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnbG9iYWwgPSBUUlVFKQpwMTcgPC0gRGltUGxvdChmaWJybywgcmVkdWN0aW9uID0gInRzbmUiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJnZ3NjaTo6ZGVmYXVsdF9uZWptIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNCkpKQpwMTcKYGBgCgojIyMgQ2VsbCBUeXBlIElkZW50aWZpY2F0aW9uCgpGaXJzdCB3ZSBpZGVudGlmeSB0aGUgZW5kb3RoZWxpYWwgYW5kIHBlcml2YXNjdWxhciBjZWxscyB1c2luZyBQTFZBUCBhbmQgUkdTNSBleHByZXNzaW9uLiAKCmBgYHtyfQpwMTggPC0gRmVhdHVyZVBsb3QoZmlicm8sIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiUExWQVAiLCBwdC5zaXplID0gMS41KSArCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHRpdGxlID0gIlBMVkFQIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMTkgPC0gRmVhdHVyZVBsb3QoZmlicm8sIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiUkdTNSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHRpdGxlID0gIlJHUzUiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwMTggfCBwMTkpIC8gcDE3CmBgYAoKCk5leHQsIHdlIHVzZSB0aGUgYFZBTWAgbWV0aG9kIG9mIHNpbmdsZSBjZWxsIGdlbmUgc2V0IGVucmljaG1lbnQgYW5hbHlzaXMgdG8gZGV0ZXJtaW5lIHdoaWNoIGNsdXN0ZXJzIGFyZSBlbnJpY2hlZCBmb3IgdGhlIGlDQUYgYW5kIG15Q0FGIG1hcmtlciBnZW5lcywgYXMgd2VsbCBhcyB0aGUgZ2VuZXJhbCBwYW4tQ0FGIG1hcmtlciBzZXQuIFdlIHVzZSB0aGUgbWFya2VyIGdlbmVzIGlkZW50aWZpZWQgYnkgdGhlIGF1dGhvcnMuIAoKYGBge3J9CmljYWZfZ2VuZXMgPC0gYygiSUw2IiwgIlBER0ZSQSIsICJDWENMMTIiLCAiQ0ZEIiwgIkxNTkEiLCAKICAgICAgICAgICAgICAgICJBR1RSMSIsICJIQVMxIiwgIkNYQ0wxIiwgIkNYQ0wyIiwgIkNDTDIiLCAiSUw4IikKbXljYWZfZ2VuZXMgPC0gYygiQUNUQTIiLCAiVEFHTE4iLCAiTU1QMTEiLCAiTVlMOSIsIAogICAgICAgICAgICAgICAgICJIT1BYIiwgIlBPU1ROIiwgIlRQTTEiLCAiVFBNMiIpCnBhbl9jYWZfZ2VuZXMgPC0gYygiQ09MMUExIiwgIkZBUCIsICJQRFBOIiwgIkRDTiIsICJWSU0iKQpnZW5lX3NldHMgPC0gbGlzdChpY2FmX2dlbmVzLCBteWNhZl9nZW5lcywgcGFuX2NhZl9nZW5lcykKbmFtZXMoZ2VuZV9zZXRzKSA8LSBjKCJpQ0FGIiwgIm15Q0FGIiwgIlBhbi1DQUYiKQpmb3IgKGkgaW4gc2VxKGdlbmVfc2V0cykpIHsKICBnZW5lX3NldHNbW2ldXSA8LSBnZW5lX3NldHNbW2ldXVtnZW5lX3NldHNbW2ldXSAlaW4lIHJvd25hbWVzKGZpYnJvKV0KfQpmaWJybyA8LSB2YW1Gb3JTZXVyYXQoZmlicm8sIAogICAgICAgICAgICAgICAgICAgICAgZ2VuZS5zZXQuY29sbGVjdGlvbiA9IGdlbmVfc2V0cywgCiAgICAgICAgICAgICAgICAgICAgICBnYW1tYSA9IFRSVUUpCkRlZmF1bHRBc3NheShmaWJybykgPC0gIlZBTWNkZiIKYGBgCgojIyMjIGlDQUZzICYgbXlDQUZzCgpXZSBjYW4gZWFzaWx5IGRlZmluZSBjbHVzdGVyIDAgYXMgdGhlIG15Q0FGIHBvcHVsYXRpb24sIGFuZCBjbHVzdGVyIDIgYXMgdGhlIHNsaWdodGx5IHNtYWxsZXIgaUNBRiBwb3B1bGF0aW9uLiBDbHVzdGVyIDQgc2hvd3Mgbm8gZW5yaWNobWVudCB3aGF0c29ldmVyIGZvciBlaXRoZXIgdGhlIGlDQUYgb3IgbXlDQUYgZ2VuZSBzZXRzLiAKCmBgYHtyfQpwMjAgPC0gRmVhdHVyZVBsb3QoZmlicm8sIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiaUNBRiIsIHB0LnNpemUgPSAxLjUpICsKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnModGl0bGUgPSAiaUNBRiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDIxIDwtIEZlYXR1cmVQbG90KGZpYnJvLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIm15Q0FGIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnModGl0bGUgPSAibXlDQUYiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwMjAgfCBwMjEpIC8gcDE3CmBgYAoKIyMjIyBhcENBRnMKClNvIHdlIGhhdmUgYSBzbWFsbCBjbHVzdGVyIG9mIDIzIGNlbGxzIHRoYXQgZG9lcyBub3QgYXBwZWFyIHRvIGV4cHJlc3MgYW55IG9mIHRoZSBmaWJyb2JsYXN0LCBDQUYsIHBlcml2YXNjdWxhciwgb3IgZW5kb3RoZWxpYWwgbWFya2Vycy4gQWZ0ZXIgcGVyZm9ybWluZyBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcywgd2UgZmluZCB0aGF0IHRoZSB0b3AgMyBtYXJrZXJzIGZvciBjbHVzdGVyIDQgYXJlIENMVSwgQ0Q3NCwgYW5kIENSWUFCLiBJbnRlcmVzdGluZ2x5LCBDTFUgYW5kIENENzQgd2VyZSBmb3VuZCB0byBiZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgaW4gdGhlIGFwQ0FGIHBvcHVsYXRpb24gZGlzY292ZXJlZCBpbiB0aGUgS1BDIG1vdXNlIG1vZGVscyBvZiBDQUZzIGluIEVseWFkYSAqZXQgYWwqLgoKYGBge3J9CkRlZmF1bHRBc3NheShmaWJybykgPC0gIlNDVCIKZmlicm9fbWFya2VycyA8LSBGaW5kQWxsTWFya2VycyhmaWJybywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzYXkgPSAiU0NUIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nZmMudGhyZXNob2xkID0gMS41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXN0LnVzZSA9ICJ3aWxjb3giLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbmx5LnBvcyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbS5zZWVkID0gNjI5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gRkFMU0UpCmZpYnJvX21hcmtlcnMgJT4lIAogIGZpbHRlcihjbHVzdGVyID09IDQpICU+JSAKICBhcnJhbmdlKGRlc2MoYXZnX2xvZzJGQykpICU+JSAKICBkcGx5cjo6c2VsZWN0KGNsdXN0ZXIsIGdlbmUsIGF2Z19sb2cyRkMsIHBfdmFsX2FkaiwgcGN0LjEsIHBjdC4yKSAlPiUgCiAgc2xpY2VfaGVhZChuID0gNSkgJT4lIAogIGtibChib29rdGFicyA9IFRSVUUsIGRpZ2l0cyA9IDQsIHJvdy5uYW1lcyA9IEZBTFNFKSAlPiUgCiAga2FibGVfbWluaW1hbCgiaG92ZXIiLCBmdWxsX3dpZHRoID0gRkFMU0UpCmBgYAoKV2UgcmUtcnVuIEdTRUEsIGFnYWluIHVzaW5nIHRoZSBgVkFNYCBwYWNrYWdlIGFuZCB0aGUgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmVzIGZvciB0aGUgYXBDQUYgcG9wdWxhdGlvbiBhcyBkZWZpbmVkIGluIEVseWFkYSAqZXQgYWwqICh3aXRoIHRoZSBtb3VzZSBnZW5lIG5hbWVzIGNvbnZlcnRlZCB0byBIR05DIHN5bWJvbHMpLiBXZSBjYW4gc2VlIHRoYXQgdGhlIGFwQ0FGIHBhdGh3YXkgaXMgc3Ryb25nbHkgZW5yaWNoZWQgaW4gY2x1c3RlciA0IGFzIGNvbXBhcmVkIHRvIHRoZSBvdGhlciBDQUYgY2x1c3RlcnMuCgpgYGB7cn0KYXBjYWZfZ2VuZXMgPC0gYygiSExBLURRQjEiLCAiQ0Q3NCIsICJTQUEzUCIsICJTTFBJIikKZ2VuZV9zZXRzIDwtIGxpc3QoaWNhZl9nZW5lcywgbXljYWZfZ2VuZXMsIGFwY2FmX2dlbmVzLCBwYW5fY2FmX2dlbmVzKQpuYW1lcyhnZW5lX3NldHMpIDwtIGMoImlDQUYiLCAibXlDQUYiLCAiYXBDQUYiLCAiUGFuLUNBRiIpCmZvciAoaSBpbiBzZXEoZ2VuZV9zZXRzKSkgewogIGdlbmVfc2V0c1tbaV1dIDwtIGdlbmVfc2V0c1tbaV1dW2dlbmVfc2V0c1tbaV1dICVpbiUgcm93bmFtZXMoZmlicm8pXQp9CmZpYnJvIDwtIHZhbUZvclNldXJhdChmaWJybywgCiAgICAgICAgICAgICAgICAgICAgICBnZW5lLnNldC5jb2xsZWN0aW9uID0gZ2VuZV9zZXRzLCAKICAgICAgICAgICAgICAgICAgICAgIGdhbW1hID0gVFJVRSkKRGVmYXVsdEFzc2F5KGZpYnJvKSA8LSAiVkFNY2RmIgpwMjIgPC0gRmVhdHVyZVBsb3QoZmlicm8sIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiYXBDQUYiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh0aXRsZSA9ICJhcENBRiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDIyIC8gcDE3CmBgYAoKIyMjIFZpc3VhbGl6YXRpb24KCkZpbmFsbHksIHdlIGFkZCBjZWxsIGxhYmVscyB0byBvdXIgaWRlbnRpZmllZCBjbHVzdGVycy4KCmBgYHtyfQpmaWJybyRsYWJlbCA8LSBjYXNlX3doZW4oZmlicm8kc2V1cmF0X2NsdXN0ZXJzID09IDAgfiAibXlDQUYiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGZpYnJvJHNldXJhdF9jbHVzdGVycyA9PSAxIH4gIlBlcml2YXNjdWxhciIsIAogICAgICAgICAgICAgICAgICAgICAgICAgZmlicm8kc2V1cmF0X2NsdXN0ZXJzID09IDIgfiAiaUNBRiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgZmlicm8kc2V1cmF0X2NsdXN0ZXJzID09IDMgfiAiRW5kb3RoZWxpYWwiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGZpYnJvJHNldXJhdF9jbHVzdGVycyA9PSA0IH4gImFwQ0FGIikKSWRlbnRzKGZpYnJvKSA8LSAibGFiZWwiCnAyM2EgPC0gRGltUGxvdChmaWJybywgcmVkdWN0aW9uID0gInRzbmUiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlZXJfZCgiZ2dzY2k6OmRlZmF1bHRfbmVqbSIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNCkpKQpwMjNhCmBgYAoKSGVyZSdzIHRoZSBtYXJrZXIgZ2VuZXMgZm9yIGVhY2ggY2x1c3Rlci4gCgpgYGB7cn0KRGVmYXVsdEFzc2F5KGZpYnJvKSA8LSAiU0NUIgpmaWJyb19tYXJrZXJzMiA8LSBGaW5kQWxsTWFya2VycyhmaWJybywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2ZjLnRocmVzaG9sZCA9IC41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdC51c2UgPSAid2lsY294IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ubHkucG9zID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbS5zZWVkID0gNjI5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IEZBTFNFKSAlPiUgCiAgICAgICAgICAgICAgICAgIGZpbHRlcihwX3ZhbF9hZGogPCAuMDUpICU+JSAKICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIAogICAgICAgICAgICAgICAgICBhcnJhbmdlKGRlc2MoYXZnX2xvZzJGQykpICU+JSAKICAgICAgICAgICAgICAgICAgc2xpY2VfaGVhZChuID0gNSkKcDIzYiA8LSBEb3RQbG90KGZpYnJvLCBmZWF0dXJlcyA9IGZpYnJvX21hcmtlcnMyJGdlbmUsIGRvdC5zY2FsZSA9IDEwKSArIAogICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSBwYWxldHRlZXJfZCgid2VzYW5kZXJzb246Olppc3NvdTEiKSkgKwogICAgICAgIGxhYnMoY29sb3IgPSAiRXhwcmVzc2lvbiIsIHNpemUgPSAiJSBFeHByZXNzZWQiKSArIAogICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSAxMiwgdmp1c3QgPSAwLjUpLCAKICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCBsZWdlbmQuanVzdGlmaWNhdGlvbiA9ICJjZW50ZXIiLCAKICAgICAgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BLCBzaXplID0gMSwgY29sb3IgPSAiYmxhY2siKSwgCiAgICAgICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwgCiAgICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCkpICsgCiAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3JiYXIodGl0bGUucG9zaXRpb24gPSAidG9wIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFyaGVpZ2h0ID0gdW5pdCgzLCB1bml0cyA9ICJjbSIpLCB0aXRsZS5oanVzdCA9IDAuNSksIAogICAgICAgICAgICAgICBzaXplID0gZ3VpZGVfbGVnZW5kKHRpdGxlLnBvc2l0aW9uID0gInRvcCIsIHRpdGxlLmhqdXN0ID0gMC41KSkKcDIzYgpgYGAKCiMjIFQgQ2VsbHMKCkdvaW5nIGJhY2sgdG8gdGhlIG1haW4gYFNldXJhdGAgb2JqZWN0LCB3ZSBzaG91bGQgaGF2ZSBhIGxhcmdlIHBvcHVsYXRpb24gb2YgVCBhbmQgTksgY2VsbHMgdGhhdCB3YXJyYW50cyBmdXJ0aGVyIGludmVzdGlnYXRpb24uIFVzaW5nIENEM0QgZXhwcmVzc2lvbiB3ZSBjYW4gZWFzaWx5IGlkZW50aWZ5IGNsdXN0ZXJzIDAsIDMsIGFuZCA3IGFzIHRoZSBtaXhlZCBUICYgTksgY2VsbHMuIFdlIGFscmVhZHkgc2VlIHNvbWUgZ29vZCBzZXBhcmF0aW9uLCBzbyByZWNsdXN0ZXJpbmcgdGhlIGNlbGxzIHNob3VsZCBoYXZlIGdvb2QgcmVzdWx0cy4gCgpgYGB7cn0KcDI0IDwtIEZlYXR1cmVQbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ0QzRCIsIHB0LnNpemUgPSAwLjc1KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAyNCAvIHAyCmBgYAoKIyMjIFR1bW9yCgpgYGB7cn0Kbmt0X3R1bW9yIDwtIHN1YnNldChwZGFjLCBzdWJzZXQgPSBzZXVyYXRfY2x1c3RlcnMgJWluJSBjKDAsIDMsIDgpICYgY29uZGl0aW9uID09ICJQREFDIikKYGBgCgojIyMjIFJlY2x1c3RlcmluZwoKSGVyZSB3ZSBydW4gYFJlY2x1c3RlckNlbGxzKClgLCB3aGlsZSB0cmVhdGluZyB0aGUgTksgJiBUIGNlbGwgY2x1c3RlcnMgYXMgb25lIGxhcmdlIGdyb3VwLiBUaGlzIHdpbGwgaG9wZWZ1bGx5IGFsbG93IHVzZSB0byBlbHVjaWRhdGUgVCBjZWxsIHN1YnR5cGVzLiBXZSB1c2UgZmV3ZXIgUENzIGZvciB0aGVzZSBjZWxscyBzaW5jZSB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBpbW11bmUgY2VsbHMgYXJlIHN1YnRsZSwgYW5kIGFkZGluZyBtb3JlIFBDcyB3aWxsIG1vc3QgbGlrZWx5IG9ubHkgY29udHJpYnV0ZSBub2lzZSB0byBvdXIgYW5hbHlzZXMuIAoKYGBge3J9Cm5rdF90dW1vciA8LSBSZWNsdXN0ZXJDZWxscyhua3RfdHVtb3IsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpY2guY2x1c3QgPSBsaXN0KDAsIDMsIDgpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lcmdlLmNsdXN0ZXJzID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLkhWRyA9IDQwMDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5QQyA9IDE1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGsudmFscyA9IGMoMzAsIDQwLCA1MCwgNjApLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc29sdXRpb24udmFscyA9IGMoLjEsIC4yLCAuMyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVkby5lbWJlZGRpbmcgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbS5zZWVkID0gNjI5KQpua3RfdHVtb3JfcGMgPC0gRW1iZWRkaW5ncyhua3RfdHVtb3IsICJwY2EiKQpgYGAKCk9uY2UgYWdhaW4gd2UnbGwgcnVuIEZpdC1TTkUgb24gdGhlIHJlY2x1c3RlcmVkIGNlbGxzLiAKCmBgYHtweXRob259CiMgaW1wb3J0IGRhdGEKbmt0X3R1bW9yX3BjID0gci5ua3RfdHVtb3JfcGMKIyBydW4gRml0LVNORQphZmZpbl9ua3RfdHVtb3IgPSBQZXJwbGV4aXR5QmFzZWROTihua3RfdHVtb3JfcGMsIHBlcnBsZXhpdHk9MTAwLCBtZXRyaWM9J2Nvc2luZScsIHJhbmRvbV9zdGF0ZT02MjkpCmluaXQgPSBpbml0aWFsaXphdGlvbi5wY2Eobmt0X3R1bW9yX3BjLCByYW5kb21fc3RhdGU9NjI5KQp0c25lX25rdF90dW1vciA9IFRTTkVFbWJlZGRpbmcoaW5pdCwgYWZmaW5fbmt0X3R1bW9yLCBuZWdhdGl2ZV9ncmFkaWVudF9tZXRob2Q9J2ZmdCcpCmVtYmVkX25rdF90dW1vcjEgPSB0c25lX25rdF90dW1vci5vcHRpbWl6ZShuX2l0ZXI9MjUwLCBleGFnZ2VyYXRpb249NCwgbW9tZW50dW09MC42KSAKZW1iZWRfbmt0X3R1bW9yMiA9IGVtYmVkX25rdF90dW1vcjEub3B0aW1pemUobl9pdGVyPTc1MCwgZXhhZ2dlcmF0aW9uPTEsIG1vbWVudHVtPTAuOCkKYWZmaW5fbmt0X3R1bW9yLnNldF9wZXJwbGV4aXR5KDUwKQplbWJlZF9ua3RfdHVtb3IzID0gZW1iZWRfbmt0X3R1bW9yMi5vcHRpbWl6ZShuX2l0ZXI9NTAwLCBleGFnZ2VyYXRpb249MSwgbW9tZW50dW09MC42KQpgYGAKClRoZSByZWVtYmVkZGluZyBpc24ndCBwZXJmZWN0LCB3aGljaCB3ZSBzb21ld2hhdCBleHBlY3RlZCBhcyBpbW11bmUgY2VsbHMgYXJlIGRpZmZpY3VsdCB0byB0ZWxsIGFwYXJ0IGJhc2VkIG9uIHRoZSB0cmFuc2NyaXB0b21lIGFsb25lLiAKCmBgYHtyfQplbWJlZF9ua3RfdHVtb3IgPC0gYXMubWF0cml4KHB5JGVtYmVkX25rdF90dW1vcjMpCnJvd25hbWVzKGVtYmVkX25rdF90dW1vcikgPC0gY29sbmFtZXMobmt0X3R1bW9yKQpua3RfdHVtb3JAcmVkdWN0aW9ucyRiaF90c25lIDwtIG5rdF90dW1vckByZWR1Y3Rpb25zJHRzbmUKbmt0X3R1bW9yQHJlZHVjdGlvbnMkdHNuZTwtIENyZWF0ZURpbVJlZHVjT2JqZWN0KGVtYmVkZGluZ3MgPSBlbWJlZF9ua3RfdHVtb3IsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2V5ID0gIkZpdFNORV8iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2F5ID0gIlNDVCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2xvYmFsID0gVFJVRSkKcDI1IDwtIERpbVBsb3Qobmt0X3R1bW9yLCByZWR1Y3Rpb24gPSAidHNuZSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoImdnc2NpOjpjYXRlZ29yeTIwX2QzIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNCkpKQpwMjUKYGBgCgojIyMjIENlbGwgVHlwZSBJZGVudGlmaWNhdGlvbgoKIyMjIyMgQ0Q0KyBUCgpDbHVzdGVycyAwIGFuZCAxIGNvbnRhaW4gb3VyIENENCsgVCBjZWxscywgd2hpY2ggd2UgY2hhcmFjdGVyaXplIHVzaW5nIElMN1IgYXMgd2UgZGlkIGluIHRoZSBQQk1DM2sgdmlnbmV0dGUuIEl0J3Mgc29tZXdoYXQgb3V0c2lkZSBvZiBvdXIgc2NvcGUgaGVyZSB0byBkZXRlcm1pbmUgd2hpY2ggc3VidHlwZSBlYWNoIGNsdXN0ZXIgYmVsb25ncyB0bywgc28gd2UnbGwgc2ltcGx5IGFzc2lnbiBib3RoIGNsdXN0ZXJzIHRoZSBzYW1lIGxhYmVsIGFuZCBtb3ZlIG9uLiAKCmBgYHtyfQpwMjYgPC0gRmVhdHVyZVBsb3Qobmt0X3R1bW9yLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIklMN1IiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMjcgPC0gRmVhdHVyZVBsb3Qobmt0X3R1bW9yLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkNENjkiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoocDI2IHwgcDI3KSAvIHAyNQpgYGAKCiMjIyMjIFQtcmVncwoKQ2x1c3RlciAzIGNvbnRhaW5zIHRoZSByZWd1bGF0b3J5IFQgY2VsbHMuIAoKYGBge3J9CnAyOCA8LSBGZWF0dXJlUGxvdChua3RfdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiSUwyUkEiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMjkgPC0gRmVhdHVyZVBsb3Qobmt0X3R1bW9yLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkZPWFAzIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHAyOCB8IHAyOSkgLyBwMjUKYGBgCgojIyMjIyBQcm9saWZlcmF0aW5nIFQtcmVncwoKV2UgY2FuIGZpbmQgdGhlIHByb2xpZmVyYXRpbmcgVC1yZWdzIGluIGNsdXN0ZXIgNy4gCgpgYGB7cn0KcDMwIDwtIEZlYXR1cmVQbG90KG5rdF90dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJUT1AyQSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAzMCAvIHAyNQpgYGAKCiMjIyMjIE1hc3QKCk1hc3QgY2VsbHMgY2FuIGJlIGlkZW50aWZpZWQgdXNpbmcgVFBTQUIxIGV4cHJlc3Npb24gaW4gY2x1c3RlciA2LiAKCmBgYHtyfQpwMzEgPC0gRmVhdHVyZVBsb3Qobmt0X3R1bW9yLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIlRQU0FCMSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAzMSAvIHAyNQpgYGAKCiMjIyMjIE5LCgpOS0c3IGFuZCBQUkYxIHNob3cgdXMgdGhlIE5LIGNlbGxzIGluIGNsdXN0ZXIgNS4gCgpgYGB7cn0KcDMyIDwtIEZlYXR1cmVQbG90KG5rdF90dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJOS0c3IiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDMzIDwtIEZlYXR1cmVQbG90KG5rdF90dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJQUkYxIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHAzMiB8IHAzMykgLyBwMjUKYGBgCgojIyMjIyBDRDgrIFQKCldlIHVzZSBDRDhBIGFuZCBDRDIgdG8gcmV2ZWFsIHRoZSBDRDgrIFQgY2VsbHMgd2l0aGluIGNsdXN0ZXJzIDIgYW5kIDQuIAoKYGBge3J9CnAzNCA8LSBGZWF0dXJlUGxvdChua3RfdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ0Q4QSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAzNSA8LSBGZWF0dXJlUGxvdChua3RfdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ0QyIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHAzNCB8IHAzNSkgLyBwMjUKYGBgCgojIyMjIEludGVybWVkaWF0ZSBNb25vY3l0ZQoKTGFzdGx5LCB3ZSBoYXZlIGNsdXN0ZXIgOCwgd2hpY2ggZG9lc24ndCBoaWdobHkgZXhwcmVzcyBvdXIgcGFuLVQvTksgY2VsbCBtYXJrZXJzIENEM0QgYW5kIENEMi4gSXQgY291bGQgYmUgYSBteWVsb2lkIGNlbGwgY2x1c3RlciB0aGF0IHdhcyBtaXN0YWtlbmx5IGdyb3VwZWQgd2l0aCB0aGUgVC9OSyBjZWxscy4gV2UnbGwgc3RhcnQgd2l0aCBhIFdpbGNveG9uIHRlc3QgdG8gZGV0ZXJtaW5lIGl0cyBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMuIEludGVyZXN0aW5nbHksIHNldmVyYWwgW2ludGVybWVkaWF0ZSBtb25vY3l0ZSBtYXJrZXJzXShodHRwczovL3d3dy5mcm9udGllcnNpbi5vcmcvYXJ0aWNsZXMvMTAuMzM4OS9maW1tdS4yMDE5LjAyMDM1L2Z1bGwjQjMpIC0gTFlaLCBITEEtRFJBLCBDRDc0LCBhbmQgSExBLURQQjEgLSBhcmUgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGluIGNsdXN0ZXIgOC4gCgpgYGB7cn0KY2x1c3Q4X21hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMobmt0X3R1bW9yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdC51c2UgPSAid2lsY294IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluLmRpZmYucGN0ID0gLjIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2ZjLnRocmVzaG9sZCA9IC41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZG9tLnNlZWQgPSA2MjkpICU+JSAKICAgICAgICAgICAgICAgICAgZmlsdGVyKGNsdXN0ZXIgPT0gOCwgcF92YWxfYWRqIDwgLjA1KSAlPiUgCiAgICAgICAgICAgICAgICAgIGFycmFuZ2UoZGVzYygxIC0gcF92YWxfYWRqKSkKY2x1c3Q4X21hcmtlcnMgJT4lIAogIGZpbHRlcihnZW5lICVpbiUgYygiTFlaIiwgIkhMQS1EUkEiLCAiQ0Q3NCIsICJITEEtRFBCMSIpKSAlPiUgCiAgZHBseXI6OnNlbGVjdChjbHVzdGVyLCBnZW5lLCBhdmdfbG9nMkZDLCBwX3ZhbF9hZGosIHBjdC4xLCBwY3QuMikgJT4lIAogIGtibChib29rdGFicyA9IFRSVUUsIGRpZ2l0cyA9IDQsIHJvdy5uYW1lcyA9IEZBTFNFKSAlPiUgCiAga2FibGVfbWluaW1hbCgiaG92ZXIiLCBmdWxsX3dpZHRoID0gRkFMU0UpCmBgYAoKV2UnbGwgcGxvdCBzb21lIG9mIHRob3NlIG1hcmtlcnMgYmVsb3cuIAoKYGBge3J9CnAzNiA8LSBGZWF0dXJlUGxvdChua3RfdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiTFlaIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDM3IDwtIEZlYXR1cmVQbG90KG5rdF90dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJITEEtRFJBIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDM4IDwtIEZlYXR1cmVQbG90KG5rdF90dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDRDc0IiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDM5IDwtIEZlYXR1cmVQbG90KG5rdF90dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJITEEtRFBCMSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCigocDM2IHwgcDM3KSAvIChwMzggfCBwMzkpKSAvIHAyNQpgYGAKCiMjIyMgVmlzdWFsaXphdGlvbgoKV2UgYWRkIGxhYmVscyB0byBvdXIgVCBjZWxsIGBTZXVyYXRgIG9iamVjdCBhbmQgdmlzdWFsaXplIHRoZSByZXN1bHRzLiAKCmBgYHtyfQpua3RfdHVtb3IkbGFiZWwgPC0gY2FzZV93aGVuKG5rdF90dW1vciRzZXVyYXRfY2x1c3RlcnMgPT0gMCB+ICJDRDQrIFQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBua3RfdHVtb3Ikc2V1cmF0X2NsdXN0ZXJzID09IDEgfiAiQ0Q0KyBUIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmt0X3R1bW9yJHNldXJhdF9jbHVzdGVycyA9PSAyIH4gIkNEOCsgVCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5rdF90dW1vciRzZXVyYXRfY2x1c3RlcnMgPT0gMyB+ICJULXJlZyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5rdF90dW1vciRzZXVyYXRfY2x1c3RlcnMgPT0gNCB+ICJDRDgrIFQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBua3RfdHVtb3Ikc2V1cmF0X2NsdXN0ZXJzID09IDUgfiAiTksiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBua3RfdHVtb3Ikc2V1cmF0X2NsdXN0ZXJzID09IDYgfiAiTWFzdCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5rdF90dW1vciRzZXVyYXRfY2x1c3RlcnMgPT0gNyB+ICJQcm9saWZlcmF0aW5nIFQtcmVnIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmt0X3R1bW9yJHNldXJhdF9jbHVzdGVycyA9PSA4IH4gIkludGVybWVkaWF0ZSBNb25vY3l0ZSIpCklkZW50cyhua3RfdHVtb3IpIDwtICJsYWJlbCIKcDQwYSA8LSBEaW1QbG90KG5rdF90dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlZXJfZCgiZ2dzY2k6OmRlZmF1bHRfbmVqbSIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMiwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNCkpKQpwNDBhCmBgYAoKSGVyZSdzIHRoZSBtYXJrZXIgZ2VuZXMuIAoKYGBge3J9Cm5rdF90dW1vcl9tYXJrZXJzMiA8LSBGaW5kQWxsTWFya2Vycyhua3RfdHVtb3IsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nZmMudGhyZXNob2xkID0gLjUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdC51c2UgPSAid2lsY294IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbmx5LnBvcyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZG9tLnNlZWQgPSA2MjksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IEZBTFNFKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIocF92YWxfYWRqIDwgLjA1KSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBncm91cF9ieShjbHVzdGVyKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBhcnJhbmdlKGRlc2MoYXZnX2xvZzJGQykpICU+JSAKICAgICAgICAgICAgICAgICAgICAgIHNsaWNlX2hlYWQobiA9IDUpCnA0MGIgPC0gRG90UGxvdChua3RfdHVtb3IsIGZlYXR1cmVzID0gdW5pcXVlKG5rdF90dW1vcl9tYXJrZXJzMiRnZW5lKSwgZG90LnNjYWxlID0gMTApICsgCiAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHBhbGV0dGVlcl9kKCJ3ZXNhbmRlcnNvbjo6Wmlzc291MSIpKSArCiAgICAgICAgbGFicyhjb2xvciA9ICJFeHByZXNzaW9uIiwgc2l6ZSA9ICIlIEV4cHJlc3NlZCIpICsgCiAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgc2l6ZSA9IDksIHZqdXN0ID0gMC41KSwgCiAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwgbGVnZW5kLmp1c3RpZmljYXRpb24gPSAiY2VudGVyIiwgCiAgICAgICAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSwgc2l6ZSA9IDEsIGNvbG9yID0gImJsYWNrIiksIAogICAgICAgICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksIAogICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpKSArIAogICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2NvbG9yYmFyKHRpdGxlLnBvc2l0aW9uID0gInRvcCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhcmhlaWdodCA9IHVuaXQoMywgdW5pdHMgPSAiY20iKSwgdGl0bGUuaGp1c3QgPSAwLjUpLCAKICAgICAgICAgICAgICAgc2l6ZSA9IGd1aWRlX2xlZ2VuZCh0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiLCB0aXRsZS5oanVzdCA9IDAuNSkpCnA0MGIKYGBgCgojIyMgQWRqYWNlbnQgTm9ybWFsCgpgYGB7cn0Kbmt0X25vcm0gPC0gc3Vic2V0KHBkYWMsIHN1YnNldCA9IHNldXJhdF9jbHVzdGVycyAlaW4lIGMoMCwgMywgOCkgJiBjb25kaXRpb24gPT0gIkFkak5vcm0iKQpgYGAKCiMjIyMgUmVjbHVzdGVyaW5nCgpgYGB7cn0Kbmt0X25vcm0gPC0gUmVjbHVzdGVyQ2VsbHMobmt0X25vcm0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICB3aGljaC5jbHVzdCA9IGxpc3QoMCwgMywgOCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBtZXJnZS5jbHVzdGVycyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBuLkhWRyA9IDQwMDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBuLlBDID0gMTAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBrLnZhbHMgPSBjKDE1LCAyMCwgMjUpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x1dGlvbi52YWxzID0gYyguMiwgLjMsIC40KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG5uLm1ldHJpYyA9ICJldWNsaWRlYW4iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVkby5lbWJlZGRpbmcgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZG9tLnNlZWQgPSA2MjkpCm5rdF9ub3JtX3BjIDwtIEVtYmVkZGluZ3Mobmt0X25vcm0sICJwY2EiKQpgYGAKCkFzIHdpdGggdGhlIG90aGVyIHJlY2x1c3RlcmluZ3MsIHdlJ2xsIHJ1biBGaXQtU05FIGluIG9yZGVyIHRvIChob3BlZnVsbHkpIG9idGFpbiBhIGJldHRlciBsb3ctZGltZW5zaW9uYWwgZW1iZWRkaW5nIG9mIG91ciBjZWxscy4KCmBgYHtweXRob259CiMgaW1wb3J0IGRhdGEKbmt0X25vcm1fcGMgPSByLm5rdF9ub3JtX3BjCiMgcnVuIEZpdC1TTkUKYWZmaW5fbmt0X25vcm0gPSBQZXJwbGV4aXR5QmFzZWROTihua3Rfbm9ybV9wYywgcGVycGxleGl0eT0zMCwgbWV0cmljPSdjb3NpbmUnLCByYW5kb21fc3RhdGU9NjI5KQppbml0ID0gaW5pdGlhbGl6YXRpb24ucGNhKG5rdF9ub3JtX3BjLCByYW5kb21fc3RhdGU9NjI5KQp0c25lX25rdF9ub3JtID0gVFNORUVtYmVkZGluZyhpbml0LCBhZmZpbl9ua3Rfbm9ybSwgbmVnYXRpdmVfZ3JhZGllbnRfbWV0aG9kPSdmZnQnKQplbWJlZF9ua3Rfbm9ybTEgPSB0c25lX25rdF9ub3JtLm9wdGltaXplKG5faXRlcj0yNTAsIGV4YWdnZXJhdGlvbj0xMiwgbW9tZW50dW09MC42KSAKZW1iZWRfbmt0X25vcm0yID0gZW1iZWRfbmt0X25vcm0xLm9wdGltaXplKG5faXRlcj03NTAsIGV4YWdnZXJhdGlvbj0xLCBtb21lbnR1bT0wLjgpCmBgYAoKYGBge3J9CmVtYmVkX25rdF9ub3JtIDwtIGFzLm1hdHJpeChweSRlbWJlZF9ua3Rfbm9ybTIpCnJvd25hbWVzKGVtYmVkX25rdF9ub3JtKSA8LSBjb2xuYW1lcyhua3Rfbm9ybSkKbmt0X25vcm1AcmVkdWN0aW9ucyRiaF90c25lIDwtIG5rdF9ub3JtQHJlZHVjdGlvbnMkdHNuZQpua3Rfbm9ybUByZWR1Y3Rpb25zJHRzbmU8LSBDcmVhdGVEaW1SZWR1Y09iamVjdChlbWJlZGRpbmdzID0gZW1iZWRfbmt0X25vcm0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZXkgPSAiRml0U05FXyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheSA9ICJTQ1QiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2xvYmFsID0gVFJVRSkKcDQxIDwtIERpbVBsb3Qobmt0X25vcm0sIHJlZHVjdGlvbiA9ICJ0c25lIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlZXJfZCgiZ2dzY2k6OmRlZmF1bHRfbmVqbSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDQpKSkKcDQxCmBgYAoKIyMjIyBDZWxsIFR5cGUgSWRlbnRpZmljYXRpb24KCkZpcnN0IHdlJ2xsIHVzZSBhIFdpbGNveG9uIHRlc3QgdG8gZGV0ZXJtaW5lIHdoaWNoIGdlbmVzIGNoYXJhY3Rlcml6ZSBlYWNoIGNsdXN0ZXIuIAoKYGBge3J9Cm5rdF9ub3JtX21hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMobmt0X25vcm0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2ZjLnRocmVzaG9sZCA9IC41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW4uZGlmZi5wY3QgPSAuMiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbmx5LnBvcyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbS5zZWVkID0gNjI5KSAlPiUgCiAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHBfdmFsX2FkaiA8IC4wNSkKbmt0X25vcm1fbWFya2VycyAgJT4lIAogIGRwbHlyOjpzZWxlY3QoY2x1c3RlciwgZ2VuZSwgYXZnX2xvZzJGQywgcF92YWxfYWRqLCBwY3QuMSwgcGN0LjIpICU+JSAKICBncm91cF9ieShjbHVzdGVyKSAlPiUgCiAgdG9wX24obiA9IDMsIHd0ID0gYXZnX2xvZzJGQykgJT4lIAogIGtibChib29rdGFicyA9IFRSVUUsIGRpZ2l0cyA9IDQpICU+JSAKICBrYWJsZV9taW5pbWFsKCJob3ZlciIsIGZ1bGxfd2lkdGggPSBGQUxTRSkKYGBgCgojIyMjIyBDRDQrIFQKCldlIGNhbiB1c2UgSUw3UiBhbmQgUzEwMEE0IGV4cHJlc3Npb24gdG8gaWRlbnRpZnkgdGhlIG1lbW9yeSBDRDQrIFQgY2VsbHMgaW4gY2x1c3RlcnMgMCAmIDIuIElMN1IgYW5kIENDUjcgaWRlbnRpZnkgdGhlIG5haXZlIENENCsgVCBjZWxscyBpbiB0aGUgYWRqYWNlbnQgY2x1c3RlciA2LiAKCmBgYHtyfQpwNDIgPC0gRmVhdHVyZVBsb3Qobmt0X25vcm0sIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiSUw3UiIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA0MyA8LSBGZWF0dXJlUGxvdChua3Rfbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJTMTAwQTQiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwNDQgPC0gRmVhdHVyZVBsb3Qobmt0X25vcm0sIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ0NSNyIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwNDIgfCBwNDMgfCBwNDQpIC8gcDQxCmBgYAoKIyMjIyMgQ0Q4KyBUCgpOZXh0IHdlIHJldmVhbCB0aGUgQ0Q4KyBUIGNlbGxzIGluIGNsdXN0ZXJzIDEgYW5kIDMgd2l0aCBDRDhBLCBhcyBwZXIgdXN1YWwuIAoKYGBge3J9CnA0NSA8LSBGZWF0dXJlUGxvdChua3Rfbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDRDhBIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDQ1IC8gcDQxCmBgYAoKIyMjIyMgVC1yZWcKClRoZSBULXJlZyBjbHVzdGVyLCBjbHVzdGVyIDUsIGlzIGlkZW50aWZpZWQgdXNpbmcgVElHSVQgYW5kIEZPWFAzLiAKCmBgYHtyfQpwNDYgPC0gRmVhdHVyZVBsb3Qobmt0X25vcm0sIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiVElHSVQiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwNDcgPC0gRmVhdHVyZVBsb3Qobmt0X25vcm0sIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiRk9YUDMiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoocDQ2IHwgcDQ3KSAvIHA0MQpgYGAKCiMjIyMjIE5LCgpUaGUgbmF0dXJhbCBraWxsZXJzIGNhbiBiZSBmb3VuZCBpbiBjbHVzdGVyIDQgdGhyb3VnaCB0aGVpciBleHByZXNzaW9uIG9mIFBSRjEgYW5kIE5LRzcuIFRoZSBOS0c3IGV4cHJlc3Npb24gYWxzbyBjb25maXJtcyB0aGUgaWRlbnRpdGllcyBvZiB0aGUgQ0Q4KyBUIGNlbGxzIHdlIGp1c3QgYW5ub3RhdGVkLiAKCmBgYHtyfQpwNDggPC0gRmVhdHVyZVBsb3Qobmt0X25vcm0sIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiUFJGMSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA0OSA8LSBGZWF0dXJlUGxvdChua3Rfbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJOS0c3IiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHA0OCB8IHA0OSkgLyBwNDEKYGBgCgojIyMjIyBQcm9saWZlcmF0aW5nIFQtcmVnCgpUaGUgdGlueSBwcm9saWZlcmF0aW5nIFQtcmVnIHBvcHVsYXRpb24gaW4gY2x1c3RlciA3IGlzIGNoYXJhY3Rlcml6ZWQgYnkgVE9QMkEuIAoKYGBge3J9CnA1MCA8LSBGZWF0dXJlUGxvdChua3Rfbm9ybSwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJUT1AyQSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA1MCAvIHA0MQpgYGAKCiMjIyMgVmlzdWFsaXphdGlvbgoKV2UgYWRkIGZpbmFsIGNlbGwgbGFiZWxzIHRvIG91ciA4IGNlbGwgY2x1c3RlcnMuIAoKYGBge3J9Cm5rdF9ub3JtJGxhYmVsIDwtIGNhc2Vfd2hlbihua3Rfbm9ybSRzZXVyYXRfY2x1c3RlcnMgPT0gMCB+ICJNZW1vcnkgQ0Q0KyBUIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBua3Rfbm9ybSRzZXVyYXRfY2x1c3RlcnMgPT0gMSB+ICJDRDgrIFQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbmt0X25vcm0kc2V1cmF0X2NsdXN0ZXJzID09IDIgfiAiTWVtb3J5IENENCsgVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBua3Rfbm9ybSRzZXVyYXRfY2x1c3RlcnMgPT0gMyB+ICJDRDgrIFQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbmt0X25vcm0kc2V1cmF0X2NsdXN0ZXJzID09IDQgfiAiTksiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbmt0X25vcm0kc2V1cmF0X2NsdXN0ZXJzID09IDUgfiAiVC1yZWciLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5rdF9ub3JtJHNldXJhdF9jbHVzdGVycyA9PSA2IH4gIk5haXZlIENENCsgVCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbmt0X25vcm0kc2V1cmF0X2NsdXN0ZXJzID09IDcgfiAiUHJvbGlmZXJhdGluZyBULXJlZyIpCklkZW50cyhua3Rfbm9ybSkgPC0gImxhYmVsIgpwNTFhIDwtIERpbVBsb3Qobmt0X25vcm0sIHJlZHVjdGlvbiA9ICJ0c25lIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoImdnc2NpOjpkZWZhdWx0X25lam0iKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDIsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDQpKSkKcDUxYQpgYGAKCkhlcmUncyB0aGUgbWFya2VyIGdlbmVzLiAKCmBgYHtyfQpua3Rfbm9ybV9tYXJrZXJzMiA8LSBGaW5kQWxsTWFya2Vycyhua3Rfbm9ybSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2ZjLnRocmVzaG9sZCA9IC41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdC51c2UgPSAid2lsY294IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ubHkucG9zID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbS5zZWVkID0gNjI5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IEZBTFNFKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIocF92YWxfYWRqIDwgLjA1KSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBncm91cF9ieShjbHVzdGVyKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBhcnJhbmdlKGRlc2MoYXZnX2xvZzJGQykpICU+JSAKICAgICAgICAgICAgICAgICAgICAgIHNsaWNlX2hlYWQobiA9IDUpCnA1MWIgPC0gRG90UGxvdChua3Rfbm9ybSwgZmVhdHVyZXMgPSB1bmlxdWUobmt0X25vcm1fbWFya2VyczIkZ2VuZSksIGRvdC5zY2FsZSA9IDEwKSArIAogICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSBwYWxldHRlZXJfZCgid2VzYW5kZXJzb246Olppc3NvdTEiKSkgKwogICAgICAgIGxhYnMoY29sb3IgPSAiRXhwcmVzc2lvbiIsIHNpemUgPSAiJSBFeHByZXNzZWQiKSArIAogICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSAxMCwgdmp1c3QgPSAwLjUpLCAKICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCBsZWdlbmQuanVzdGlmaWNhdGlvbiA9ICJjZW50ZXIiLCAKICAgICAgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BLCBzaXplID0gMSwgY29sb3IgPSAiYmxhY2siKSwgCiAgICAgICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwgCiAgICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCkpICsgCiAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3JiYXIodGl0bGUucG9zaXRpb24gPSAidG9wIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFyaGVpZ2h0ID0gdW5pdCgzLCB1bml0cyA9ICJjbSIpLCB0aXRsZS5oanVzdCA9IDAuNSksIAogICAgICAgICAgICAgICBzaXplID0gZ3VpZGVfbGVnZW5kKHRpdGxlLnBvc2l0aW9uID0gInRvcCIsIHRpdGxlLmhqdXN0ID0gMC41KSkKcDUxYgpgYGAKCiMjIER1Y3RhbCBDZWxscwoKIyMjIFJlY2x1c3RlcmluZwoKV2UgdXNlIEtSVDggZXhwcmVzc2lvbiB0byBzaG93IHRoZSBkdWN0YWwgY2VsbHMgcmVzaWRpbmcgaW4gY2x1c3RlcnMgNSBhbmQgOS4gV2Ugbm90ZSB0aGF0IHNvbWUgcmVnaW9ucyBvZiBjbHVzdGVycyA1IGFuZCA5IGhhdmUgbm8gS1JUOCBleHByZXNzaW9uLCB3aGljaCBsaWtlbHkgbWVhbnMgdGhhdCB0aGV5IGFyZSBjb21wb3NlZCBvZiBkaWZmZXJlbnQgY2VsbCB0eXBlcy4gCgpgYGB7cn0KcDUyIDwtIEZlYXR1cmVQbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiS1JUOCIsIHB0LnNpemUgPSAwLjc1KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwNTIgLyBwMgpgYGAKCldlIHJ1biBgU0NJU1NPUlNgLCB0aGVuIHVzZSBhIFdpbGNveG9uIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIHRlc3QgdG8gZGV0ZXJtaW5lIHBvdGVudGlhbCBtYXJrZXJzIGZvciBlYWNoIGNsdXN0ZXIuIAoKYGBge3J9CmR1Y3RhbCA8LSBSZWNsdXN0ZXJDZWxscyhwZGFjLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoLmNsdXN0ID0gbGlzdCg1LCA5KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBtZXJnZS5jbHVzdGVycyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgbi5IVkcgPSA0MDAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgIG4uUEMgPSAyMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICBrLnZhbHMgPSBjKDIwLCAzMCwgNDAsIDUwKSwgbm4ubWV0cmljID0gImV1Y2xpZGVhbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x1dGlvbi52YWxzID0gYyguMiwgLjMsIC40KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICByZWRvLmVtYmVkZGluZyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgcmFuZG9tLnNlZWQgPSA2MjkpCmR1Y3RhbF9tYXJrZXJzIDwtIEZpbmRBbGxNYXJrZXJzKGR1Y3RhbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2ZjLnRocmVzaG9sZCA9IC41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluLmRpZmYucGN0ID0gLjIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbmx5LnBvcyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb20uc2VlZCA9IDYyOSkgJT4lIAogICAgICAgICAgICAgICAgICBmaWx0ZXIocF92YWxfYWRqIDwgLjA1KQpkdWN0YWxfbWFya2VycyAlPiUgCiAgZHBseXI6OnNlbGVjdChjbHVzdGVyLCBnZW5lLCBhdmdfbG9nMkZDLCBwX3ZhbF9hZGosIHBjdC4xLCBwY3QuMikgJT4lIAogIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSAKICB0b3BfbihuID0gMywgd3QgPSBhdmdfbG9nMkZDKSAlPiUgCiAga2JsKGJvb2t0YWJzID0gVFJVRSwgZGlnaXRzID0gNCkgJT4lIAogIGthYmxlX21pbmltYWwoImhvdmVyIiwgZnVsbF93aWR0aCA9IEZBTFNFKQpgYGAKCkFnYWluLCB3ZSdsbCBydW4gRml0LVNORSBvbiB0aGUgcmVjbHVzdGVyZWQgY2VsbHMuIAoKYGBge3J9CmR1Y3RfcGMgPC0gRW1iZWRkaW5ncyhkdWN0YWwsIHJlZHVjdGlvbiA9ICJwY2EiKQpgYGAKCmBgYHtweXRob259CiMgaW1wb3J0IGRhdGEKZHVjdF9wYyA9IHIuZHVjdF9wYwojIHJ1biBGaXQtU05FCmFmZmluX2R1Y3QgPSBQZXJwbGV4aXR5QmFzZWROTihkdWN0X3BjLCBwZXJwbGV4aXR5PTMwLCByYW5kb21fc3RhdGU9NjI5KQppbml0ID0gaW5pdGlhbGl6YXRpb24ucGNhKGR1Y3RfcGMsIHJhbmRvbV9zdGF0ZT02MjkpCnRzbmVfZHVjdCA9IFRTTkVFbWJlZGRpbmcoaW5pdCwgYWZmaW5fZHVjdCwgbmVnYXRpdmVfZ3JhZGllbnRfbWV0aG9kPSdmZnQnKQplbWJlZF9kMSA9IHRzbmVfZHVjdC5vcHRpbWl6ZShuX2l0ZXI9MjUwLCBleGFnZ2VyYXRpb249MTAsIG1vbWVudHVtPTAuNikKZW1iZWRfZDIgPSBlbWJlZF9kMS5vcHRpbWl6ZShuX2l0ZXI9NzUwLCBleGFnZ2VyYXRpb249MSwgbW9tZW50dW09MC44KQpgYGAKCldlIHB1bGwgdGhlIHJlc3VsdHMgaW50byBSLCBtYWtpbmcgc3VyZSB0byBzYXZlIHRoZSBCYXJuZXMtSHV0IHQtU05FIHJlc3VsdHMgaW4gYW5vdGhlciByZWR1Y3Rpb24gc2xvdC4KCmBgYHtyfQplbWJlZF9kdWN0IDwtIGFzLm1hdHJpeChweSRlbWJlZF9kMikKcm93bmFtZXMoZW1iZWRfZHVjdCkgPC0gY29sbmFtZXMoZHVjdGFsKQpkdWN0YWxAcmVkdWN0aW9ucyRiaF90c25lIDwtIGR1Y3RhbEByZWR1Y3Rpb25zJHRzbmUKZHVjdGFsQHJlZHVjdGlvbnMkdHNuZTwtIENyZWF0ZURpbVJlZHVjT2JqZWN0KGVtYmVkZGluZ3MgPSBlbWJlZF9kdWN0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleSA9ICJGaXRTTkVfIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheSA9ICJTQ1QiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdsb2JhbCA9IFRSVUUpCnA1MyA8LSBEaW1QbG90KGR1Y3RhbCwgcmVkdWN0aW9uID0gInRzbmUiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJnZ3NjaTo6ZGVmYXVsdF9uZWptIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNCkpKQpwNTMKYGBgCgojIyMgQ2VsbCBUeXBlIElkZW50aWZpY2F0aW9uIAoKIyMjIyBMaXBpZCBQcm9jZXNzaW5nCgpXZSB1c2UgQU5QRVAgJiBGQUJQMSBleHByZXNzaW9uIHRvIGlkZW50aWZ5IHRoZSBsaXBpZCBwcm9jZXNzaW5nIGR1Y3RhbCBjZWxscyBpbiBjbHVzdGVyIDYuIAoKYGBge3J9CnA1NCA8LSBGZWF0dXJlUGxvdChkdWN0YWwsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQU5QRVAiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwNTUgPC0gRmVhdHVyZVBsb3QoZHVjdGFsLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkZBQlAxIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHA1NCB8IHA1NSkgLyBwNTMKYGBgCgojIyMjIFNlY3JldG9yeQoKRXhwcmVzc2lvbiBvZiBTT0QzIGFuZCBDRlRSIHJldmVhbHMgdGhlIHNlY3JldG9yeSBjZWxscyBpbiBjbHVzdGVyIDMuCgpgYGB7cn0KcDU2IDwtIEZlYXR1cmVQbG90KGR1Y3RhbCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJTT0QzIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDU3IDwtIEZlYXR1cmVQbG90KGR1Y3RhbCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDRlRSIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHA1NiB8IHA1NykgLyBwNTMKYGBgCgojIyMjIENsYXNzaWNhbCAxCgpXZSB1c2UgVEZGMSBhbmQgVEZGMiBleHByZXNzaW9uIHRvIGFubm90YXRlIHRoZSBjbGFzc2ljYWwgMSBlcGl0aGVsaWFsIGNlbGxzIGluIGNsdXN0ZXJzIDAgYW5kIDEuIFdlIGNhbiBhbHNvIHNlZSB0aGF0IHRoZSB0d28gY2xhc3NpY2FsIDEgY2x1c3RlcnMgYXJlIHNwbGl0IGJ5IHRoZSBzYW1wbGUgZnJvbSB3aGljaCB0aGUgY2VsbHMgb3JpZ2luYXRlLiBHb2luZyBmb3J3YXJkLCB3ZSdsbCBzaW1wbHkgbGFiZWwgYm90aCBjbHVzdGVycyBhcyBjbGFzc2ljYWwgMS4gCgpgYGB7cn0KcDU4IDwtIEZlYXR1cmVQbG90KGR1Y3RhbCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJURkYxIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDU5IDwtIEZlYXR1cmVQbG90KGR1Y3RhbCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJURkYyIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDYwIDwtIERpbVBsb3QoZHVjdGFsLCByZWR1Y3Rpb24gPSAidHNuZSIsIGdyb3VwLmJ5ID0gInNhbXBsZSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoIm1pc2NwYWxldHRlczo6YnJpZ2h0UGFzdGVsIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJTYW1wbGUiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwNTggfCBwNjAgfCBwNTkpIC8gcDUzCmBgYAoKIyMjIyBDbGFzc2ljYWwgMgoKVGhlIGNsYXNzaWNhbCAyIGNlbGxzIGFyZSBsb2NhdGVkIGluIGNsdXN0ZXIgNiwgYXMgZXZpZGVuY2VkIGJ5IHRoZWlyIGV4cHJlc3Npb24gb2YgQ1JJU1AzLiAKCmBgYHtyfQpwNjEgPC0gRmVhdHVyZVBsb3QoZHVjdGFsLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkNSSVNQMyIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA2MSAvIHA1MwpgYGAKCiMjIyMgQmFzYWwtbGlrZQoKVGhlIGJhc2FsIGNvbXBhcnRtZW50IHdlaWdodHMgZnJvbSBgREVDT0RFUmAgYXJlIGhpZ2hlc3QgaW4gY2x1c3RlciA0LCB3aGljaCB3ZSB3aWxsIGRlbm90ZSBhcyBiZWluZyBjb21wb3NlZCBvZiBiYXNhbC1saWtlIFBEQUMuIAoKYGBge3J9CnA2MiA8LSBGZWF0dXJlUGxvdChkdWN0YWwsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiYmFzYWwiKSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIiwgdGl0bGUgPSAiQmFzYWwiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA2MiAvIHA1MwpgYGAKCiMjIyMgQWNpbmFyCgpMYXN0bHksIHdlIHNob3cgdGhhdCBjbHVzdGVyIDIgaXMgY29tcG9zZWQgb2YgYWNpbmFyIGNlbGxzIHVzaW5nIENUUkIyLgoKYGBge3J9CnA2MyA8LSBGZWF0dXJlUGxvdChkdWN0YWwsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ1RSQjIiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwNjMgLyBwNTMKYGBgCgojIyMgVmlzdWFsaXphdGlvbgoKV2UgYWRkIGZpbmFsIGNsdXN0ZXIgbGFiZWxzIHRvIG91ciBgU2V1cmF0YCBvYmplY3QgYW5kIHZpc3VhbGl6ZSB0aGUgcmVzdWx0cy4KCmBgYHtyfQpkdWN0YWwkbGFiZWwgPC0gY2FzZV93aGVuKGR1Y3RhbCRzZXVyYXRfY2x1c3RlcnMgPT0gMCB+ICJDbGFzc2ljYWwgMSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGR1Y3RhbCRzZXVyYXRfY2x1c3RlcnMgPT0gMSB+ICJDbGFzc2ljYWwgMSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGR1Y3RhbCRzZXVyYXRfY2x1c3RlcnMgPT0gMiB+ICJBY2luYXIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBkdWN0YWwkc2V1cmF0X2NsdXN0ZXJzID09IDMgfiAiU2VjcmV0b3J5IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZHVjdGFsJHNldXJhdF9jbHVzdGVycyA9PSA0IH4gIkJhc2FsIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZHVjdGFsJHNldXJhdF9jbHVzdGVycyA9PSA1IH4gIkxpcGlkIFByb2MuIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZHVjdGFsJHNldXJhdF9jbHVzdGVycyA9PSA2IH4gIkNsYXNzaWNhbCAyIikKSWRlbnRzKGR1Y3RhbCkgPC0gImxhYmVsIgpwNjRhIDwtIERpbVBsb3QoZHVjdGFsLCByZWR1Y3Rpb24gPSAidHNuZSIscHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoImdnc2NpOjpkZWZhdWx0X25lam0iKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDQpKSkKcDY0YQpgYGAKCkhlcmUncyB0aGUgbWFya2VyIGdlbmVzLiAKCmBgYHtyfQpkdWN0YWxfbWFya2VyczIgPC0gRmluZEFsbE1hcmtlcnMoZHVjdGFsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2ZjLnRocmVzaG9sZCA9IC41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3QudXNlID0gIndpbGNveCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25seS5wb3MgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbS5zZWVkID0gNjI5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2UgPSBGQUxTRSkgJT4lIAogICAgICAgICAgICAgICAgICAgZmlsdGVyKHBfdmFsX2FkaiA8IC4wNSkgJT4lIAogICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIAogICAgICAgICAgICAgICAgICAgYXJyYW5nZShkZXNjKGF2Z19sb2cyRkMpKSAlPiUgCiAgICAgICAgICAgICAgICAgICBzbGljZV9oZWFkKG4gPSA1KQpwNjRiIDwtIERvdFBsb3QoZHVjdGFsLCBmZWF0dXJlcyA9IHVuaXF1ZShkdWN0YWxfbWFya2VyczIkZ2VuZSksIGRvdC5zY2FsZSA9IDEwKSArIAogICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSBwYWxldHRlZXJfZCgid2VzYW5kZXJzb246Olppc3NvdTEiKSkgKwogICAgICAgIGxhYnMoY29sb3IgPSAiRXhwcmVzc2lvbiIsIHNpemUgPSAiJSBFeHByZXNzZWQiKSArIAogICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSAxMiwgdmp1c3QgPSAwLjUpLCAKICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCBsZWdlbmQuanVzdGlmaWNhdGlvbiA9ICJjZW50ZXIiLCAKICAgICAgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BLCBzaXplID0gMSwgY29sb3IgPSAiYmxhY2siKSwgCiAgICAgICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwgCiAgICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCkpICsgCiAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfY29sb3JiYXIodGl0bGUucG9zaXRpb24gPSAidG9wIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFyaGVpZ2h0ID0gdW5pdCgzLCB1bml0cyA9ICJjbSIpLCB0aXRsZS5oanVzdCA9IDAuNSksIAogICAgICAgICAgICAgICBzaXplID0gZ3VpZGVfbGVnZW5kKHRpdGxlLnBvc2l0aW9uID0gInRvcCIsIHRpdGxlLmhqdXN0ID0gMC41KSkKcDY0YgpgYGAKCiMjIFBsYXNtYSBDZWxscyAmIFBsYXNtYWN5dG9pZCBEQ3MKCldlIHVzZSBKQ0hBSU4gKGRlbm90ZWQgSUdKIGluIEVseWFkYSAqZXQgYWwqKSB0byByZXZlYWwgdGhlIFBsYXNtYSBjZWxscyBpbiBjbHVzdGVyIDEwLCBhbmQgSVJGNyB0byBpZGVudGlmeSB0aGUgcGxhc21hY3l0b2lkIERDcyBpbiBjbHVzdGVyIDExLiAKCmBgYHtyfQpwNjUgPC0gRmVhdHVyZVBsb3QocGRhYywgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJKQ0hBSU4iLCBwdC5zaXplID0gMC43NSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIkpDSEFJTiAoSUdKKSIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDY2IDwtIEZlYXR1cmVQbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiSVJGNyIsIHB0LnNpemUgPSAwLjc1KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIiwgdGl0bGUgPSAiSVJGNyIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHA2NSB8IHA2NikgLyBwMgpgYGAKCiMjIEIgQ2VsbHMKCldlIGNhbiBpZGVudGlmeSB0aGUgQiBjZWxscyBpbiBjbHVzdGVyIDQgdXNpbmcgam9pbnQgZXhwcmVzc2lvbiBvZiBNUzRBMSBhbmQgQ0Q3OUEuIFRoZSBjbHVzdGVyIGlzIHNwbGl0IGludG8gdHdvIHN1YmNsdXN0ZXJzIGJ5IHRpc3N1ZSB0eXBlOiBhZGphY2VudCBub3JtYWwgYW5kIFBEQUMuIFdoaWxlIGl0IHdvdWxkIGJlIGludGVyZXN0aW5nIHRvIGRldGVybWluZSB0aGUgZ2VuZXRpYyBkcml2ZXJzIG9mIHRoYXQgc2VwYXJhdGlvbiwgaXQncyBzb21ld2hhdCBvdXRzaWRlIG9mIG91ciBzY29wZSBoZXJlLiAKCmBgYHtyfQpwNjcgPC0gRmVhdHVyZVBsb3QocGRhYywgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJNUzRBMSIsIHB0LnNpemUgPSAwLjc1KSArCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJNUzRBMSIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDY4IDwtIEZlYXR1cmVQbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ0Q3OUEiLCBwdC5zaXplID0gMC43NSkgKwogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIiwgdGl0bGUgPSAiQ0Q3OUEiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA2OSA8LSBEaW1QbG90KHBkYWMsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZ3JvdXAuYnkgPSAiY29uZGl0aW9uIiwgcHQuc2l6ZSA9IDAuNzUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoIm1pc2NwYWxldHRlczo6YnJpZ2h0UGFzdGVsIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJUaXNzdWUgVHlwZSIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHA2NyB8IHA2OSB8IHA2OCkgLyBwMgpgYGAKCiMjIE15ZWxvaWQgQ2VsbHMKCkxhc3RseSwgd2UnbGwgc3BsaXQgdXAgdGhlIG15ZWxvaWQgcG9wdWxhdGlvbiBieSB0aXNzdWUgY29uZGl0aW9uIChQREFDIHZzLiBhZGphY2VudCBub3JtYWwpIGp1c3QgbGlrZSB3ZSBkaWQgd2l0aCB0aGUgTksgLyBUIGNlbGxzLiBXZSdsbCBydW4gYFNDSVNTT1JTYCwgYW5ub3RhdGUgdGhlIGNsdXN0ZXJzLCBhbmQgdmlzdWFsaXplIHRoZSByZXN1bHRzLiAKCiMjIyBUdW1vciAKCkZpcnN0IHdlJ2xsIGF0dGVtcHQgdG8gYXNzaWduIGJyb2FkIGNlbGwgdHlwZSBsYWJlbHMgdG8gZWFjaCBvZiB0aGUgZm91ciBwdXRhdGl2ZSBteWVsb2lkIGNsdXN0ZXJzLiBXZSdsbCB1c2UgdGhlIG1hcmtlciBnZW5lcyBmcm9tIEVseWFkYSAqZXQgYWwqIG9uY2UgYWdhaW4uIAoKYGBge3J9Cm15b190dW1vciA8LSBzdWJzZXQocGRhYywgc3Vic2V0ID0gc2V1cmF0X2NsdXN0ZXJzICVpbiUgYygxLCAyLCA3KSAmIGNvbmRpdGlvbiA9PSAiUERBQyIpCnA3MCA8LSBEaW1QbG90KG15b190dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJnZ3NjaTo6ZGVmYXVsdF9uZWptIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDQpKSkKcDcwCmBgYAoKQ2x1c3RlciAxIGFwcGVhcnMgdG8gYmUgY29tcG9zZWQgb2Ygb3VyIHJlc2lkZW50ICYgYWx0ZXJuYXRpdmVseSBhY3RpdmF0ZWQgbWFjcm9waGFnZXMgZHVlIHRvIGl0cyBleHByZXNzaW9uIG9mIENEMTQgJiBDMVFBIGFuZCBTUFAxLCByZXNwZWN0aXZlbHkuIAoKYGBge3J9CnA3MSA8LSBGZWF0dXJlUGxvdChteW9fdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ0QxNCIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJDRDE0IikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwNzIgPC0gRmVhdHVyZVBsb3QobXlvX3R1bW9yLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkMxUUEiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIiwgdGl0bGUgPSAiQzFRQSIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDczIDwtIEZlYXR1cmVQbG90KG15b190dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJTUFAxIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIlNQUDEiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwNzEgfCBwNzIgfCBwNzMpIC8gcDcwCmBgYAoKV2UgY2FuIHVzZSBMWVogYW5kIFMxMDBBOCBleHByZXNzaW9uIHRvIHJldmVhbCB0aGUgY2xhc3NpYyBtb25vY3l0ZXMgYW5kIG5ldXRyb3BoaWxzIGluIGNsdXN0ZXIgMi4gCgpgYGB7cn0KcDc0IDwtIEZlYXR1cmVQbG90KG15b190dW1vciwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJMWVoiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIiwgdGl0bGUgPSAiTFlaIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwNzUgPC0gRmVhdHVyZVBsb3QobXlvX3R1bW9yLCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIlMxMDBBOCIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJTMTAwQTgiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwNzQgfCBwNzUpIC8gcDcwCmBgYAoKTGFzdGx5LCB3ZSBzaG93IHRoYXQgY2x1c3RlciA2IGNvbnRhaW5zIG91ciB2YXJpb3VzIERDIHN1YnR5cGVzIHRocm91Z2ggaXRzIGV4cHJlc3Npb24gb2YgRkNFUjFBLCBhIGNhbm9uaWNhbCBkZW5kcml0aWMgY2VsbCBtYXJrZXIuIAoKYGBge3J9CnA3NiA8LSBGZWF0dXJlUGxvdChteW9fdHVtb3IsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiRkNFUjFBIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIkZDRVIxQSIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDc2IC8gcDcwCmBgYAoKIyMjIyBSZWNsdXN0ZXJpbmcKCldlJ2xsIHN0YXJ0IHdpdGggdGhlIE1hY3JvcGhhZ2VzICYgTW9ub2N5dGVzLCBzaW5jZSB0aGUgREMgcG9wdWxhdGlvbnMgYXJlIHNtYWxsIGFuZCBhcmUgYmVzdCBkZWFsdCB3aXRoIG9uIHRoZWlyIG93bi4gCgpgYGB7cn0KbXlvX3JlY2x1c3QgPC0gUmVjbHVzdGVyQ2VsbHMobXlvX3R1bW9yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpY2guY2x1c3QgPSBjKDEsIDIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5QQyA9IDE1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVyZ2UuY2x1c3RlcnMgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgay52YWxzID0gYyg0MCwgNTAsIDYwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc29sdXRpb24udmFscyA9IGMoLjIsIC4zLCAuNCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLkhWRyA9IDQwMDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWRvLmVtYmVkZGluZyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb20uc2VlZCA9IDYyOSkKZGNfcmVjbHVzdCA8LSBSZWNsdXN0ZXJDZWxscyhteW9fdHVtb3IsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoLmNsdXN0ID0gNywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5QQyA9IDE1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrLnZhbHMgPSBjKDIwLCAzMCwgNDAsIDUwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x1dGlvbi52YWxzID0gYyguMywgLjQsIC41KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbi5IVkcgPSA0MDAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBubi5tZXRyaWMgPSAiZXVjbGlkZWFuIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVkby5lbWJlZGRpbmcgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb20uc2VlZCA9IDYyOSkKYGBgCgpXZSdsbCBhZ2FpbiBydW4gRml0LVNORSBvbiBvdXIgcmVjbHVzdGVyZWQgY2VsbHMuIAoKYGBge3J9Cm1vbm9fdHVtb3JfcGMgPC0gRW1iZWRkaW5ncyhteW9fcmVjbHVzdCwgInBjYSIpCmRjX3R1bW9yX3BjIDwtIEVtYmVkZGluZ3MoZGNfcmVjbHVzdCwgInBjYSIpCmBgYAoKYGBge3B5dGhvbn0KIyBpbXBvcnQgZGF0YQptb25vX3BjID0gci5tb25vX3R1bW9yX3BjCmRjX3BjID0gci5kY190dW1vcl9wYwojIEZpdC1TTkUgLSBtb25vY3l0ZXMgJiBtYWNyb3BoYWdlcwphZmZpbl9tb25vID0gUGVycGxleGl0eUJhc2VkTk4obW9ub19wYywgcGVycGxleGl0eT0zMCwgbWV0cmljPSdjb3NpbmUnLCByYW5kb21fc3RhdGU9NjI5KQppbml0ID0gaW5pdGlhbGl6YXRpb24ucGNhKG1vbm9fcGMsIHJhbmRvbV9zdGF0ZT02MjkpCnRzbmVfbW9ubyA9IFRTTkVFbWJlZGRpbmcoaW5pdCwgYWZmaW5fbW9ubywgbmVnYXRpdmVfZ3JhZGllbnRfbWV0aG9kPSdmZnQnKQplbWJlZF9tb25vMSA9IHRzbmVfbW9uby5vcHRpbWl6ZShuX2l0ZXI9MjUwLCBleGFnZ2VyYXRpb249MTAsIG1vbWVudHVtPTAuNikKZW1iZWRfbW9ubzIgPSBlbWJlZF9tb25vMS5vcHRpbWl6ZShuX2l0ZXI9NzUwLCBleGFnZ2VyYXRpb249MSwgbW9tZW50dW09MC44KQojIEZpdC1TTkUgLSBEQwphZmZpbl9kYyA9IFBlcnBsZXhpdHlCYXNlZE5OKGRjX3BjLCBwZXJwbGV4aXR5PTMwLCByYW5kb21fc3RhdGU9NjI5KQppbml0ID0gaW5pdGlhbGl6YXRpb24ucGNhKGRjX3BjLCByYW5kb21fc3RhdGU9NjI5KQp0c25lX2RjID0gVFNORUVtYmVkZGluZyhpbml0LCBhZmZpbl9kYywgbmVnYXRpdmVfZ3JhZGllbnRfbWV0aG9kPSdmZnQnKQplbWJlZF9kYzEgPSB0c25lX2RjLm9wdGltaXplKG5faXRlcj0yNTAsIGV4YWdnZXJhdGlvbj0xMiwgbW9tZW50dW09MC42KQplbWJlZF9kYzIgPSBlbWJlZF9kYzEub3B0aW1pemUobl9pdGVyPTc1MCwgZXhhZ2dlcmF0aW9uPTEsIG1vbWVudHVtPTAuOCkKYGBgCgpXZSBwdWxsIHRoZSByZXN1bHRzIGJhY2sgaW50byBSIGFuZCB2aXN1YWxpemUgdGhlbS4gCgpgYGB7cn0KZW1iZWRfbW9ubyA8LSBhcy5tYXRyaXgocHkkZW1iZWRfbW9ubzIpCnJvd25hbWVzKGVtYmVkX21vbm8pIDwtIGNvbG5hbWVzKG15b19yZWNsdXN0KQpteW9fcmVjbHVzdEByZWR1Y3Rpb25zJGJoX3RzbmUgPC0gbXlvX3JlY2x1c3RAcmVkdWN0aW9ucyR0c25lCm15b19yZWNsdXN0QHJlZHVjdGlvbnMkdHNuZTwtIENyZWF0ZURpbVJlZHVjT2JqZWN0KGVtYmVkZGluZ3MgPSBlbWJlZF9tb25vLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2V5ID0gIkZpdFNORV8iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzYXkgPSAiU0NUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2xvYmFsID0gVFJVRSkKcDc3IDwtIERpbVBsb3QobXlvX3JlY2x1c3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlZXJfZCgiZ2dzY2k6OmRlZmF1bHRfbmVqbSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSA0KSkpCnA3NwpgYGAKCmBgYHtyfQplbWJlZF9kYyA8LSBhcy5tYXRyaXgocHkkZW1iZWRfZGMyKQpyb3duYW1lcyhlbWJlZF9kYykgPC0gY29sbmFtZXMoZGNfcmVjbHVzdCkKZGNfcmVjbHVzdEByZWR1Y3Rpb25zJGJoX3RzbmUgPC0gZGNfcmVjbHVzdEByZWR1Y3Rpb25zJHRzbmUKZGNfcmVjbHVzdEByZWR1Y3Rpb25zJHRzbmU8LSBDcmVhdGVEaW1SZWR1Y09iamVjdChlbWJlZGRpbmdzID0gZW1iZWRfZGMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleSA9ICJGaXRTTkVfIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzYXkgPSAiU0NUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnbG9iYWwgPSBUUlVFKQpwNzggPC0gRGltUGxvdChkY19yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoImdnc2NpOjpkZWZhdWx0X25lam0iKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNCkpKQpwNzgKYGBgCgojIyMjIENlbGwgVHlwZSBJZGVudGlmaWNhdGlvbgoKIyMjIyMgTW9ub2N0eWVzLCBNYWNyb3BoYWdlcywgJiBOZXV0cm9waGlscwoKRmlyc3Qgd2UgSUQgdGhlIG5ldXRyb3BoaWxzIGluIGNsdXN0ZXIgMiB1c2luZyBTMTAwQTggYW5kIFMxMDBBOSAtIG1hcmtlciBnZW5lcyB1c2VkIGJ5IEVseWFkYSAqZXQgYWwqLiAKCmBgYHtyfQpwNzkgPC0gRmVhdHVyZVBsb3QobXlvX3JlY2x1c3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiUzEwMEE4IiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIlMxMDBBOCIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDgwIDwtIEZlYXR1cmVQbG90KG15b19yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIlMxMDBBOSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJTMTAwQTkiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwNzkgfCBwODApIC8gcDc3CmBgYAoKV2UgY2FuIGlkZW50aWZ5IHRoZSBjbGFzc2ljYWwgbW9ub2N5dGVzIGluIGNsdXN0ZXIgMSB0aHJvdWdoIHRoZWlyIGV4cHJlc3Npb24gb2YgQ0QxNCBhbmQgbGFjayBvZiBleHByZXNzaW9uIG9mIENEMTYgYWthIEZDR1IzQSwgZXhwcmVzc2lvbiBvZiB3aGljaCwgYWxvbmdzaWRlIHRoYXQgb2YgTVM0QTcsIHJldmVhbHMgdGhlIGdyb3VwIG9mIENEMTYrIG1vbm9jeXRlcyBpbiBjbHVzdGVyIDQuIEZpbmFsbHksIGV4cHJlc3Npb24gb2YgdGhvc2UgZ2VuZXMgW2FzIHdlbGwgYXMgUzEwMEExMF0oaHR0cHM6Ly93d3cuZnJvbnRpZXJzaW4ub3JnL2FydGljbGVzLzEwLjMzODkvZmltbXUuMjAxOS4wMjAzNS9mdWxsI0IzKSBhbGxvd3MgdXMgdG8gZGVmaW5lZCBjbHVzdGVyIDUgYXMgY29udGFpbmluZyBpbnRlcm1lZGlhdGUgbW9ub2N5dGVzLiAKCmBgYHtyfQpwODEgPC0gRmVhdHVyZVBsb3QobXlvX3JlY2x1c3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ0QxNCIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJDRDE0IikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwODIgPC0gRmVhdHVyZVBsb3QobXlvX3JlY2x1c3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiRkNHUjNBIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIkZDR1IzQSAoQ0QxNikiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA4MyA8LSBGZWF0dXJlUGxvdChteW9fcmVjbHVzdCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJNUzRBNyIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJNUzRBNyIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDg0IDwtIEZlYXR1cmVQbG90KG15b19yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIlMxMDBBMTAiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIiwgdGl0bGUgPSAiUzEwMEExMCIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHA4MSB8IHA4MiB8IHA4MyB8IHA4NCkgLyBwNzcKYGBgCgpFeHByZXNzaW9uIG9mIEMxUUEsIEFQT0UsIGFuZCBTUFAxIHNob3cgdXMgdGhlIHJlc2lkZW50IGFuZCBhbHRlcm5hdGl2ZWx5IGFjdGl2YXRlZCBtYWNyb3BoYWdlcyBpbiBjbHVzdGVycyAwIGFuZCAzLCByZXNwZWN0aXZlbHkuIAoKYGBge3J9CnA4NSA8LSBGZWF0dXJlUGxvdChteW9fcmVjbHVzdCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDMVFBIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIkMxUUEiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA4NiA8LSBGZWF0dXJlUGxvdChteW9fcmVjbHVzdCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJBUE9FIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIkFQT0UiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA4NyA8LSBGZWF0dXJlUGxvdChteW9fcmVjbHVzdCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJTUFAxIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIlNQUDEiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwODUgfCBwODYgfCBwODcpIC8gcDc3CmBgYAoKV2UgYWRkIGNlbGwgbGFiZWxzIHRvIG91ciBgU2V1cmF0YCBvYmplY3QsIHRoZW4gd2UncmUgb2ZmIHRvIHRoZSBEQ3MuIAoKYGBge3J9Cm15b19yZWNsdXN0JGxhYmVsIDwtIGNhc2Vfd2hlbihteW9fcmVjbHVzdCRzZXVyYXRfY2x1c3RlcnMgPT0gMCB+ICJSZXNpZGVudCBNYWNyb3BoYWdlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBteW9fcmVjbHVzdCRzZXVyYXRfY2x1c3RlcnMgPT0gMSB+ICJDbGFzc2ljYWwgTW9ub2N5dGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG15b19yZWNsdXN0JHNldXJhdF9jbHVzdGVycyA9PSAyIH4gIk5ldXRyb3BoaWwiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG15b19yZWNsdXN0JHNldXJhdF9jbHVzdGVycyA9PSAzIH4gIkFsdC4gQWN0aXZhdGVkIE1hY3JvcGhhZ2UiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG15b19yZWNsdXN0JHNldXJhdF9jbHVzdGVycyA9PSA0IH4gIkNEMTYrIE1vbm9jeXRlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBteW9fcmVjbHVzdCRzZXVyYXRfY2x1c3RlcnMgPT0gNSB+ICJJbnRlcm1lZGlhdGUgTW9ub2N5dGUiKQpJZGVudHMobXlvX3JlY2x1c3QpIDwtICJsYWJlbCIKYGBgCgojIyMjIyBEZW5kcml0aWMgQ2VsbHMKCldlIGNhbiB1c2UgQ0xFQzlBIHRvIGFubm90YXRlIHRoZSBjREMxIHBvcHVsYXRpb24gaW4gY2x1c3RlciA1LiAKCmBgYHtyfQpwODggPC0gRmVhdHVyZVBsb3QoZGNfcmVjbHVzdCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDTEVDOUEiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIiwgdGl0bGUgPSAiQ0xFQzlBIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwODggLyBwNzgKYGBgCgpIaWdoIGFuZCBsb3cgZXhwcmVzc2lvbiBvZiBDRDFBIGFuZCBDRDIwNyByZXZlYWwgdGhlIExhbmdlcmhhbnMtbGlrZSBEQ0IgYW5kIERDQSBjZWxscyBpbiBjbHVzdGVycyAzIGFuZCA0LCByZXNwZWN0aXZlbHkuIAoKYGBge3J9CnA4OSA8LSBGZWF0dXJlUGxvdChkY19yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkNEMUEiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIiwgdGl0bGUgPSAiQ0QxQSIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDkwIDwtIEZlYXR1cmVQbG90KGRjX3JlY2x1c3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ0QyMDciLCBwdC5zaXplID0gMS41KSArIAogICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIiwgdGl0bGUgPSAiQ0QyMDciKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwODkgfCBwOTApIC8gcDc4CmBgYAoKTmV4dCB3ZSB1c2UgTEFNUDMgdG8gaWRlbnRpZnkgdGhlIGFjdGl2YXRlZCBEQ3MgaW4gY2x1c3RlciA2LiAKCmBgYHtyfQpwOTEgPC0gRmVhdHVyZVBsb3QoZGNfcmVjbHVzdCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJMQU1QMyIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiLCB0aXRsZSA9ICJMQU1QMyIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDkxIC8gcDc4CmBgYAoKTGFzdGx5LCB3ZSB1c2UgZXhwcmVzc2lvbiBvZiB0d28gW2Nhbm9uaWNhbCBjREMyIG1hcmtlciBnZW5lcyAvIHRyYW5zY3JpcHRpb24gZmFjdG9yc10oaHR0cHM6Ly9vbmxpbmVsaWJyYXJ5LndpbGV5LmNvbS9kb2kvcGRmLzEwLjExMTEvaW1tLjEyODg4KSB0byBpZGVudGlmeSBjbHVzdGVycyAwLCAxLCBhbmQgMiBhcyBjREMyIGNlbGxzLCB3aGljaCBhcmUgc3BsaXQgYnkgc2FtcGxlIElELiAKCmBgYHtyfQpwOTIgPC0gRmVhdHVyZVBsb3QoZGNfcmVjbHVzdCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDTEVDMTBBIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDkzIDwtIEZlYXR1cmVQbG90KGRjX3JlY2x1c3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiS0xGNCIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnA5NCA8LSBEaW1QbG90KGRjX3JlY2x1c3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZ3JvdXAuYnkgPSAic2FtcGxlIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlZXJfZCgibWlzY3BhbGV0dGVzOjpicmlnaHRQYXN0ZWwiKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIlNhbXBsZSIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHA5MiB8IHA5NCB8IHA5MykgLyBwNzgKYGBgCgpXZSBhZGQgZmluYWwgc3ViY2x1c3RlciBjZWxsIHR5cGUgbGFiZWxzIHRvIG91ciBgU2V1cmF0YCBvYmplY3QsIHRoZW4gd2UncmUgb2ZmIHRvIHRoZSBhZGphY2VudCBub3JtYWwgbXllbG9pZCBjZWxscy4gCgpgYGB7cn0KZGNfcmVjbHVzdCRsYWJlbCA8LSBjYXNlX3doZW4oZGNfcmVjbHVzdCRzZXVyYXRfY2x1c3RlcnMgPT0gMCB+ICJjREMyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRjX3JlY2x1c3Qkc2V1cmF0X2NsdXN0ZXJzID09IDEgfiAiY0RDMiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkY19yZWNsdXN0JHNldXJhdF9jbHVzdGVycyA9PSAyIH4gImNEQzIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGNfcmVjbHVzdCRzZXVyYXRfY2x1c3RlcnMgPT0gMyB+ICJMYW5nZXJoYW5zLWxpa2UgRENCIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRjX3JlY2x1c3Qkc2V1cmF0X2NsdXN0ZXJzID09IDQgfiAiTGFuZ2VyaGFucy1saWtlIERDQSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkY19yZWNsdXN0JHNldXJhdF9jbHVzdGVycyA9PSA1IH4gImNEQzEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGNfcmVjbHVzdCRzZXVyYXRfY2x1c3RlcnMgPT0gNiB+ICJBY3RpdmF0ZWQgREMiKQpJZGVudHMoZGNfcmVjbHVzdCkgPC0gImxhYmVsIgpgYGAKCiMjIyMgVmlzdWFsaXphdGlvbgoKIyMjIyMgTW9ub2N5dGVzICYgTmV1dHJvcGhpbHMKCmBgYHtyfQpwOTVhIDwtIERpbVBsb3QobXlvX3JlY2x1c3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoImdnc2NpOjpkZWZhdWx0X25lam0iKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDIsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDQpKSkKcDk1YQpgYGAKCkhlcmUncyB0aGUgbWFya2VyIGdlbmVzLiAKCmBgYHtyfQpteW9fcmVjbHVzdF9tYXJrZXJzMiA8LSBGaW5kQWxsTWFya2VycyhteW9fcmVjbHVzdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2ZjLnRocmVzaG9sZCA9IC41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdC51c2UgPSAid2lsY294IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ubHkucG9zID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbS5zZWVkID0gNjI5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IEZBTFNFKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihwX3ZhbF9hZGogPCAuMDUpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICBhcnJhbmdlKGRlc2MoYXZnX2xvZzJGQykpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgc2xpY2VfaGVhZChuID0gNSkKcDk1YiA8LSBEb3RQbG90KG15b19yZWNsdXN0LCBmZWF0dXJlcyA9IHVuaXF1ZShteW9fcmVjbHVzdF9tYXJrZXJzMiRnZW5lKSwgZG90LnNjYWxlID0gMTApICsgCiAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHBhbGV0dGVlcl9kKCJ3ZXNhbmRlcnNvbjo6Wmlzc291MSIpKSArCiAgICAgICAgbGFicyhjb2xvciA9ICJFeHByZXNzaW9uIiwgc2l6ZSA9ICIlIEV4cHJlc3NlZCIpICsgCiAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgc2l6ZSA9IDksIHZqdXN0ID0gMC41KSwgCiAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwgbGVnZW5kLmp1c3RpZmljYXRpb24gPSAiY2VudGVyIiwgCiAgICAgICAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSwgc2l6ZSA9IDEsIGNvbG9yID0gImJsYWNrIiksIAogICAgICAgICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksIAogICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpKSArIAogICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2NvbG9yYmFyKHRpdGxlLnBvc2l0aW9uID0gInRvcCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhcmhlaWdodCA9IHVuaXQoMywgdW5pdHMgPSAiY20iKSwgdGl0bGUuaGp1c3QgPSAwLjUpLCAKICAgICAgICAgICAgICAgc2l6ZSA9IGd1aWRlX2xlZ2VuZCh0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiLCB0aXRsZS5oanVzdCA9IDAuNSkpCnA5NWIKYGBgCgojIyMjIyBEQ3MKCmBgYHtyfQpwOTZhIDwtIERpbVBsb3QoZGNfcmVjbHVzdCwgcmVkdWN0aW9uID0gInRzbmUiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlZXJfZCgiZ2dzY2k6OmRlZmF1bHRfbmVqbSIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMiwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMykpKQpwOTZhCmBgYAoKSGVyZSdzIHRoZSBtYXJrZXIgZ2VuZXMuIAoKYGBge3J9CmRjX3JlY2x1c3RfbWFya2VyczIgPC0gRmluZEFsbE1hcmtlcnMoZGNfcmVjbHVzdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nZmMudGhyZXNob2xkID0gLjUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3QudXNlID0gIndpbGNveCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ubHkucG9zID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZG9tLnNlZWQgPSA2MjksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2UgPSBGQUxTRSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihwX3ZhbF9hZGogPCAuMDUpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICBncm91cF9ieShjbHVzdGVyKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgYXJyYW5nZShkZXNjKGF2Z19sb2cyRkMpKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgc2xpY2VfaGVhZChuID0gNSkKcDk2YiA8LSBEb3RQbG90KGRjX3JlY2x1c3QsIGZlYXR1cmVzID0gdW5pcXVlKGRjX3JlY2x1c3RfbWFya2VyczIkZ2VuZSksIGRvdC5zY2FsZSA9IDgpICsgCiAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHBhbGV0dGVlcl9kKCJ3ZXNhbmRlcnNvbjo6Wmlzc291MSIpKSArCiAgICAgICAgbGFicyhjb2xvciA9ICJFeHByZXNzaW9uIiwgc2l6ZSA9ICIlIEV4cHJlc3NlZCIpICsgCiAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgc2l6ZSA9IDksIHZqdXN0ID0gMC41KSwgCiAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwgbGVnZW5kLmp1c3RpZmljYXRpb24gPSAiY2VudGVyIiwgCiAgICAgICAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSwgc2l6ZSA9IDEsIGNvbG9yID0gImJsYWNrIiksIAogICAgICAgICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksIAogICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpKSArIAogICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2NvbG9yYmFyKHRpdGxlLnBvc2l0aW9uID0gInRvcCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhcmhlaWdodCA9IHVuaXQoMywgdW5pdHMgPSAiY20iKSwgdGl0bGUuaGp1c3QgPSAwLjUpLCAKICAgICAgICAgICAgICAgc2l6ZSA9IGd1aWRlX2xlZ2VuZCh0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiLCB0aXRsZS5oanVzdCA9IDAuNSkpCnA5NmIKYGBgCgojIyMgQWRqYWNlbnQgTm9ybWFsCgpXZSBoYXZlIHRoZSBzYW1lIGZvdXIgY2x1c3RlcnMgYXMgaW4gdGhlIHR1bW9yIHRpc3N1ZSAtIDEsIDIsICYgNyAtIGFuZCB3ZSdsbCBydW4gdGhlIHNhbWUgYW5hbHlzaXMgc3RlcHMuICAKCmBgYHtyfQpteW9fbm9ybSA8LSBzdWJzZXQocGRhYywgc3Vic2V0ID0gc2V1cmF0X2NsdXN0ZXJzICVpbiUgYygxLCAyLCA3KSAmIGNvbmRpdGlvbiA9PSAiQWRqTm9ybSIpCmBgYAoKIyMjIyBSZWNsdXN0ZXJpbmcKCmBgYHtyfQpteW9fbm9ybV9yZWNsdXN0IDwtIFJlY2x1c3RlckNlbGxzKG15b19ub3JtLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aGljaC5jbHVzdCA9IGMoMSwgMiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uUEMgPSAxNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVyZ2UuY2x1c3RlcnMgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrLnZhbHMgPSBjKDIwLCAzMCwgNDApLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNvbHV0aW9uLnZhbHMgPSBjKC4xLCAuMiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4uSFZHID0gNDAwMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVkby5lbWJlZGRpbmcgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb20uc2VlZCA9IDYyOSkKZGNfbm9ybV9yZWNsdXN0IDwtIFJlY2x1c3RlckNlbGxzKG15b19ub3JtLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoLmNsdXN0ID0gNywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLlBDID0gMTUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgay52YWxzID0gYygyMCwgMzAsIDQwLCA1MCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x1dGlvbi52YWxzID0gYyguMywgLjQsIC41KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLkhWRyA9IDQwMDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm4ubWV0cmljID0gImV1Y2xpZGVhbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVkby5lbWJlZGRpbmcgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbS5zZWVkID0gNjI5KQpgYGAKCkZvciB0aGUgbGFzdCB0aW1lLCB3ZSBydW4gRml0LVNORSBpbiBvcmRlciB0byBvYnRhaW4gYSBiZXR0ZXIgZW1iZWRkaW5nLiAKCmBgYHtyfQptb25vX25vcm1fcGMgPC0gRW1iZWRkaW5ncyhteW9fbm9ybV9yZWNsdXN0LCAicGNhIikKZGNfbm9ybV9wYyA8LSBFbWJlZGRpbmdzKGRjX25vcm1fcmVjbHVzdCwgInBjYSIpCmBgYAoKYGBge3B5dGhvbn0KIyBpbXBvcnQgZGF0YQptb25vX3BjID0gci5tb25vX25vcm1fcGMKZGNfcGMgPSByLmRjX25vcm1fcGMKIyBGaXQtU05FIC0gbW9ub2N5dGVzCmFmZmluX21vbm8gPSBQZXJwbGV4aXR5QmFzZWROTihtb25vX3BjLCBwZXJwbGV4aXR5PTMwLCBtZXRyaWM9J2Nvc2luZScsIHJhbmRvbV9zdGF0ZT02MjkpCmluaXQgPSBpbml0aWFsaXphdGlvbi5wY2EobW9ub19wYywgcmFuZG9tX3N0YXRlPTYyOSkKdHNuZV9tb25vID0gVFNORUVtYmVkZGluZyhpbml0LCBhZmZpbl9tb25vLCBuZWdhdGl2ZV9ncmFkaWVudF9tZXRob2Q9J2ZmdCcpCmVtYmVkX21vbm8xID0gdHNuZV9tb25vLm9wdGltaXplKG5faXRlcj0yNTAsIGV4YWdnZXJhdGlvbj0xMCwgbW9tZW50dW09MC42KQplbWJlZF9tb25vMiA9IGVtYmVkX21vbm8xLm9wdGltaXplKG5faXRlcj03NTAsIGV4YWdnZXJhdGlvbj0xLCBtb21lbnR1bT0wLjgpCiMgRml0LVNORSAtIERDCmFmZmluX2RjID0gUGVycGxleGl0eUJhc2VkTk4oZGNfcGMsIHBlcnBsZXhpdHk9MzAsIG1ldHJpYz0nY29zaW5lJywgcmFuZG9tX3N0YXRlPTYyOSkKaW5pdCA9IGluaXRpYWxpemF0aW9uLnBjYShkY19wYywgcmFuZG9tX3N0YXRlPTYyOSkKdHNuZV9kYyA9IFRTTkVFbWJlZGRpbmcoaW5pdCwgYWZmaW5fZGMsIG5lZ2F0aXZlX2dyYWRpZW50X21ldGhvZD0nZmZ0JykKZW1iZWRfZGMxID0gdHNuZV9kYy5vcHRpbWl6ZShuX2l0ZXI9MjUwLCBleGFnZ2VyYXRpb249OCwgbW9tZW50dW09MC42KQplbWJlZF9kYzIgPSBlbWJlZF9kYzEub3B0aW1pemUobl9pdGVyPTc1MCwgZXhhZ2dlcmF0aW9uPTEsIG1vbWVudHVtPTAuOCkKYGBgCgpXZSBwdWxsIHRoZSByZXN1bHRzIGJhY2sgaW50byBSIGFuZCB2aXN1YWxpemUgdGhlbS4gCgpgYGB7cn0KZW1iZWRfbW9ubyA8LSBhcy5tYXRyaXgocHkkZW1iZWRfbW9ubzIpCnJvd25hbWVzKGVtYmVkX21vbm8pIDwtIGNvbG5hbWVzKG15b19ub3JtX3JlY2x1c3QpCm15b19ub3JtX3JlY2x1c3RAcmVkdWN0aW9ucyRiaF90c25lIDwtIG15b19ub3JtX3JlY2x1c3RAcmVkdWN0aW9ucyR0c25lCm15b19ub3JtX3JlY2x1c3RAcmVkdWN0aW9ucyR0c25lPC0gQ3JlYXRlRGltUmVkdWNPYmplY3QoZW1iZWRkaW5ncyA9IGVtYmVkX21vbm8sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleSA9ICJGaXRTTkVfIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXNzYXkgPSAiU0NUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnbG9iYWwgPSBUUlVFKQpwOTcgPC0gRGltUGxvdChteW9fbm9ybV9yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoImdnc2NpOjpkZWZhdWx0X25lam0iKSkgKyAKICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNCkpKQpwOTcKYGBgCgpgYGB7cn0KZW1iZWRfZGMgPC0gYXMubWF0cml4KHB5JGVtYmVkX2RjMikKcm93bmFtZXMoZW1iZWRfZGMpIDwtIGNvbG5hbWVzKGRjX25vcm1fcmVjbHVzdCkKZGNfbm9ybV9yZWNsdXN0QHJlZHVjdGlvbnMkYmhfdHNuZSA8LSBkY19ub3JtX3JlY2x1c3RAcmVkdWN0aW9ucyR0c25lCmRjX25vcm1fcmVjbHVzdEByZWR1Y3Rpb25zJHRzbmU8LSBDcmVhdGVEaW1SZWR1Y09iamVjdChlbWJlZGRpbmdzID0gZW1iZWRfZGMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2V5ID0gIkZpdFNORV8iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2F5ID0gIlNDVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnbG9iYWwgPSBUUlVFKQpwOTggPC0gRGltUGxvdChkY19ub3JtX3JlY2x1c3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlZXJfZCgiZ2dzY2k6OmRlZmF1bHRfbmVqbSIpKSArIAogICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSA0KSkpCnA5OApgYGAKCiMjIyMgQ2VsbCBUeXBlIElkZW50aWZpY2F0aW9uCgojIyMjIyBNb25vY3l0ZXMsIE1hY3JvcGhhZ2VzLCAmIE5ldXRyb3BoaWxzCgpXZSB1c2UgaGlnaCBTMTAwQTggYW5kIFMxMDBBOSBleHByZXNzaW9uIHRvIGRlZmluZSB0aGUgbmV1dHJvcGhpbHMgaW4gY2x1c3RlciA0LiAKCmBgYHtyfQpwOTkgPC0gRmVhdHVyZVBsb3QobXlvX25vcm1fcmVjbHVzdCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJTMTAwQTgiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAxMDAgPC0gRmVhdHVyZVBsb3QobXlvX25vcm1fcmVjbHVzdCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJTMTAwQTkiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCihwOTkgfCBwMTAwKSAvIHA5NwpgYGAKCk5leHQgdXAgYXJlIHRoZSBjbGFzc2ljYWwgbW9ub2N5dGVzIGluIGNsdXN0ZXJzIDAgYW5kIDMsIHNwbGl0IGJ5IHNhbXBsZS4gCgpgYGB7cn0KcDEwMSA8LSBGZWF0dXJlUGxvdChteW9fbm9ybV9yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkxZWiIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDEwMiA8LSBGZWF0dXJlUGxvdChteW9fbm9ybV9yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkNEMTQiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAxMDMgPC0gRGltUGxvdChteW9fbm9ybV9yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIGdyb3VwLmJ5ID0gInNhbXBsZSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJtaXNjcGFsZXR0ZXM6OmJyaWdodFBhc3RlbCIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIsIHRpdGxlID0gIlNhbXBsZSIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHAxMDEgfCBwMTAyIHwgcDEwMykgLyBwOTcKYGBgCgpDMVFBIGFuZCBBUE9FIHNob3cgdXMgdGhlIHJlc2lkZW50IG1hY3JvcGhhZ2VzIGluIGNsdXN0ZXJzIDEgYW5kIDIuIAoKYGBge3J9CnAxMDQgPC0gRmVhdHVyZVBsb3QobXlvX25vcm1fcmVjbHVzdCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDMVFBIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMTA1IDwtIEZlYXR1cmVQbG90KG15b19ub3JtX3JlY2x1c3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQVBPRSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHAxMDQgfCBwMTA1KSAvIHA5NwpgYGAKCkxhc3RseSwgaXQgc2VlbXMgd2UgaGF2ZSBhIHNtYWxsIGdyb3VwIG9mIENEOCsgVCBjZWxscyBpbiBjbHVzdGVyIDUgdGhhdCBzbnVjayBpbnRvIHRoZSBteWVsb2lkIGNsdXN0ZXIsIGFzIGRlZmluZWQgYnkgdGhlaXIgZXhwcmVzc2lvbiBvZiBDRDNEIChtYXJraW5nIHRoZW0gYXMgTksgLyBUIGNlbGxzKSwgYW5kIENEOEEgJiBOS0c3LiBJIGRvbid0IGJlbGlldmUgdGhleSdyZSBOSyBjZWxscyBhcyB0aGV5IGRvIG5vdCBleHByZXNzIFBSRjEgb3IgR1pNQi4gCgpgYGB7cn0KcDEwNiA8LSBGZWF0dXJlUGxvdChteW9fbm9ybV9yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkNEM0QiKSArIAogICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICAgICAgICBsYWJzKHggPSAiRml0LVNORSAxIiwgeSA9ICJGaXQtU05FIDIiKSArIAogICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICAgTm9MZWdlbmQoKSArIAogICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCnAxMDcgPC0gRmVhdHVyZVBsb3QobXlvX25vcm1fcmVjbHVzdCwgcmVkdWN0aW9uID0gInRzbmUiLCBmZWF0dXJlcyA9ICJDRDhBIikgKyAKICAgICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKCJaaXNzb3UxIikpICsgCiAgICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgICB0aGVtZV95ZWhsYWIoKSArIAogICAgICAgIE5vTGVnZW5kKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpwMTA4IDwtIEZlYXR1cmVQbG90KG15b19ub3JtX3JlY2x1c3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiTktHNyIpICsgCiAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHAxMDYgfCBwMTA3IHwgcDEwOCkgLyBwOTcKYGBgCgpXZSBhZGQgbGFiZWxzIHRvIG91ciBjbHVzdGVycy4gCgpgYGB7cn0KbXlvX25vcm1fcmVjbHVzdCRsYWJlbCA8LSBjYXNlX3doZW4obXlvX25vcm1fcmVjbHVzdCRzZXVyYXRfY2x1c3RlcnMgPT0gMCB+ICJDbGFzc2ljYWwgTW9ub2N5dGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXlvX25vcm1fcmVjbHVzdCRzZXVyYXRfY2x1c3RlcnMgPT0gMSB+ICJSZXNpZGVudCBNYWNyb3BoYWdlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG15b19ub3JtX3JlY2x1c3Qkc2V1cmF0X2NsdXN0ZXJzID09IDIgfiAiUmVzaWRlbnQgTWFjcm9waGFnZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBteW9fbm9ybV9yZWNsdXN0JHNldXJhdF9jbHVzdGVycyA9PSAzIH4gIkNsYXNzaWNhbCBNb25vY3l0ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBteW9fbm9ybV9yZWNsdXN0JHNldXJhdF9jbHVzdGVycyA9PSA0IH4gIk5ldXRyb3BoaWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBteW9fbm9ybV9yZWNsdXN0JHNldXJhdF9jbHVzdGVycyA9PSA1IH4gIkNEOCsgVCIpCklkZW50cyhteW9fbm9ybV9yZWNsdXN0KSA8LSAibGFiZWwiCmBgYAoKIyMjIyMgRGVuZHJpdGljIENlbGxzCgpXZSBhbm5vdGF0ZSBjbHVzdGVyIDEgYXMgY29udmVudGlvbmFsIERDMSBhbmQgY2x1c3RlciAwIGFzIGNvbnZlbnRpb25hbCBEQzIgdGhyb3VnaCBtdXR1YWxseSBleGNsdXNpdmUgZXhwcmVzc2lvbiBvZiB0aGUgY2Fub25pY2FsIG1hcmtlcnMgQ0xFQzlBIGFuZCBDTEVDMTBBLCByZXNwZWN0aXZlbHkuIAoKYGBge3J9CnAxMDkgPC0gRmVhdHVyZVBsb3QoZGNfbm9ybV9yZWNsdXN0LCByZWR1Y3Rpb24gPSAidHNuZSIsIGZlYXR1cmVzID0gIkNMRUM5QSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKcDExMCA8LSBGZWF0dXJlUGxvdChkY19ub3JtX3JlY2x1c3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZmVhdHVyZXMgPSAiQ0xFQzEwQSIsIHB0LnNpemUgPSAxLjUpICsgCiAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZSgiWmlzc291MSIpKSArIAogICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICBOb0xlZ2VuZCgpICsgCiAgICAgICAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKKHAxMDkgfCBwMTEwKSAvIHA5OApgYGAKCkxhYmVscyBhcmUgYWRkZWQgdG8gb3VyIGFkamFjZW50IG5vcm1hbCB0aXNzdWUgREMgYFNldXJhdGAgb2JqZWN0LiAKCmBgYHtyfQpkY19ub3JtX3JlY2x1c3QkbGFiZWwgPC0gY2FzZV93aGVuKGRjX25vcm1fcmVjbHVzdCRzZXVyYXRfY2x1c3RlcnMgPT0gMCB+ICJjREMyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGNfbm9ybV9yZWNsdXN0JHNldXJhdF9jbHVzdGVycyA9PSAxIH4gImNEQzIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkY19ub3JtX3JlY2x1c3Qkc2V1cmF0X2NsdXN0ZXJzID09IDIgfiAiY0RDMSIpCklkZW50cyhkY19ub3JtX3JlY2x1c3QpIDwtICJsYWJlbCIKYGBgCgojIyMjIFZpc3VhbGl6YXRpb24KCkhlcmUgYXJlIHRoZSBmaW5hbCBhbm5vdGF0aW9ucyBmb3IgdGhlIGFkamFjZW50IG5vcm1hbCB0aXNzdWUgbXllbG9pZCBwb3B1bGF0aW9uLiAKCmBgYHtyfQpwMTExYSA8LSBEaW1QbG90KG15b19ub3JtX3JlY2x1c3QsIHJlZHVjdGlvbiA9ICJ0c25lIiwgcHQuc2l6ZSA9IDEuNSkgKyAKICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGVlcl9kKCJnZ3NjaTo6ZGVmYXVsdF9uZWptIikpICsgCiAgICAgICAgIGxhYnMoeCA9ICJGaXQtU05FIDEiLCB5ID0gIkZpdC1TTkUgMiIpICsgCiAgICAgICAgIHRoZW1lX3llaGxhYigpICsgCiAgICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgCiAgICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gNCkpKQpwMTExYQpgYGAKCkFuZCBoZXJlJ3MgdGhlaXIgbWFya2VyIGdlbmVzLiAKCmBgYHtyfQpteW9fbm9ybV9yZWNsdXN0X21hcmtlcnMyIDwtIEZpbmRBbGxNYXJrZXJzKG15b19ub3JtX3JlY2x1c3QsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2ZjLnRocmVzaG9sZCA9IC41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXN0LnVzZSA9ICJ3aWxjb3giLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbmx5LnBvcyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmRvbS5zZWVkID0gNjI5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gRkFMU0UpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIocF92YWxfYWRqIDwgLjA1KSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFycmFuZ2UoZGVzYyhhdmdfbG9nMkZDKSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNsaWNlX2hlYWQobiA9IDUpCnAxMTFiIDwtIERvdFBsb3QobXlvX25vcm1fcmVjbHVzdCwgZmVhdHVyZXMgPSB1bmlxdWUobXlvX25vcm1fcmVjbHVzdF9tYXJrZXJzMiRnZW5lKSwgZG90LnNjYWxlID0gMTApICsgCiAgICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSBwYWxldHRlZXJfZCgid2VzYW5kZXJzb246Olppc3NvdTEiKSkgKwogICAgICAgICBsYWJzKGNvbG9yID0gIkV4cHJlc3Npb24iLCBzaXplID0gIiUgRXhwcmVzc2VkIikgKyAKICAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgc2l6ZSA9IDEyLCB2anVzdCA9IDAuNSksIAogICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCBsZWdlbmQuanVzdGlmaWNhdGlvbiA9ICJjZW50ZXIiLCAKICAgICAgICAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSwgc2l6ZSA9IDEsIGNvbG9yID0gImJsYWNrIiksIAogICAgICAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwgCiAgICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCkpICsgCiAgICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2NvbG9yYmFyKHRpdGxlLnBvc2l0aW9uID0gInRvcCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXJoZWlnaHQgPSB1bml0KDMsIHVuaXRzID0gImNtIiksIHRpdGxlLmhqdXN0ID0gMC41KSwgCiAgICAgICAgICAgICAgICBzaXplID0gZ3VpZGVfbGVnZW5kKHRpdGxlLnBvc2l0aW9uID0gInRvcCIsIHRpdGxlLmhqdXN0ID0gMC41KSkKcDExMWIKYGBgCgpIZXJlJ3MgdGhlIGZpbmFsIERDIGFubm90YXRpb25zIC4KCmBgYHtyfQpwMTEyYSA8LSBEaW1QbG90KGRjX25vcm1fcmVjbHVzdCwgcmVkdWN0aW9uID0gInRzbmUiLCBwdC5zaXplID0gMS41KSArIAogICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZWVyX2QoImdnc2NpOjpkZWZhdWx0X25lam0iKSkgKyAKICAgICAgICAgbGFicyh4ID0gIkZpdC1TTkUgMSIsIHkgPSAiRml0LVNORSAyIikgKyAKICAgICAgICAgdGhlbWVfeWVobGFiKCkgKyAKICAgICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAKICAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSA0KSkpCnAxMTJhCmBgYAoKQW5kIGhlcmUgYXJlIHRoZWlyIG1hcmtlciBnZW5lcy4gCgpgYGB7cn0KZGNfbm9ybV9yZWNsdXN0X21hcmtlcnMyIDwtIEZpbmRBbGxNYXJrZXJzKGRjX25vcm1fcmVjbHVzdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dmYy50aHJlc2hvbGQgPSAuNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXN0LnVzZSA9ICJ3aWxjb3giLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ubHkucG9zID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kb20uc2VlZCA9IDYyOSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gRkFMU0UpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihwX3ZhbF9hZGogPCAuMDUpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFycmFuZ2UoZGVzYyhhdmdfbG9nMkZDKSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2xpY2VfaGVhZChuID0gNSkKcDExMmIgPC0gRG90UGxvdChkY19ub3JtX3JlY2x1c3QsIGZlYXR1cmVzID0gdW5pcXVlKGRjX25vcm1fcmVjbHVzdF9tYXJrZXJzMiRnZW5lKSwgZG90LnNjYWxlID0gMTApICsgCiAgICAgICAgIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSBwYWxldHRlZXJfZCgid2VzYW5kZXJzb246Olppc3NvdTEiKSkgKwogICAgICAgICBsYWJzKGNvbG9yID0gIkV4cHJlc3Npb24iLCBzaXplID0gIiUgRXhwcmVzc2VkIikgKyAKICAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgc2l6ZSA9IDE0LCB2anVzdCA9IDAuNSksIAogICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCAKICAgICAgICAgICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSAiY2VudGVyIiwgCiAgICAgICAgICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEsIHNpemUgPSAxLCBjb2xvciA9ICJibGFjayIpLCAKICAgICAgICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksIAogICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpKSArIAogICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9jb2xvcmJhcih0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFyaGVpZ2h0ID0gdW5pdCgzLCB1bml0cyA9ICJjbSIpLCB0aXRsZS5oanVzdCA9IDAuNSksIAogICAgICAgICAgICAgICAgc2l6ZSA9IGd1aWRlX2xlZ2VuZCh0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiLCB0aXRsZS5oanVzdCA9IDAuNSkpCnAxMTJiCmBgYAoKIyBDb25jbHVzaW9ucwoKCgojIFNhdmUgRmlndXJlcyAmIERhdGEKCldlJ2xsIGNyZWF0ZSBhIHF1aWNrIGNvbnZlbmllbmNlIGZ1bmN0aW9uIHRvIGhlbHAgdXMgc2F2ZSB0aGUgZmlndXJlcy4KCmBgYHtyfQpTYXZlRmlndXJlIDwtIGZ1bmN0aW9uKG15LnBsb3QgPSBOVUxMLCBuYW1lID0gTlVMTCwgaGVpZ2h0ID0gOCwgd2lkdGggPSA4KSB7CiAgaWYgKGlzLm51bGwocGxvdCkgfCBpcy5udWxsKG5hbWUpKSBzdG9wKCJZb3UgZm9yZ290IHNvbWUgYXJndW1lbnRzLiIpCiAgIyBzYXZlIGZpZ3VyZSBhcyBpcyAtIHcvIGF4aXMgbGFiZWxzLCB0aXRsZXMsIGV0Yy4gCiAgZGlyIDwtICJ+L0Rlc2t0b3AvUi9TQ0lTU09SUy92aWduZXR0ZXMvZmlndXJlc19zdXBwL0VseWFkYSIKICBnZ3NhdmUobXkucGxvdCwgCiAgICAgICAgIGZpbGVuYW1lID0gcGFzdGUwKG5hbWUsICIucGRmIiksIAogICAgICAgICBkZXZpY2UgPSAicGRmIiwgCiAgICAgICAgIHVuaXRzID0gImluIiwKICAgICAgICAgcGF0aCA9IGRpciwgCiAgICAgICAgIGhlaWdodCA9IGhlaWdodCwgCiAgICAgICAgIHdpZHRoID0gd2lkdGgpIAogICMgc2F2ZSAiYmxhbmsiIGZpZ3VyZSB3LyBubyBsYWJlbHMsIGxlZ2VuZHMsIGV0Yy4KICBkaXIgPC0gIn4vRGVza3RvcC9SL1NDSVNTT1JTL3ZpZ25ldHRlcy9maWd1cmVzX3B1Yi9FbHlhZGEiCiAgcGxvdF9ibGFuayA8LSBteS5wbG90ICsgCiAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgICAgICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgICAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgICAgICAgICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKICBnZ3NhdmUocGxvdF9ibGFuaywgCiAgICAgICAgIGZpbGVuYW1lID0gcGFzdGUwKG5hbWUsICIucGRmIiksIAogICAgICAgICBkZXZpY2UgPSAicGRmIiwgCiAgICAgICAgIHVuaXRzID0gImluIiwKICAgICAgICAgcGF0aCA9IGRpciwgCiAgICAgICAgIGhlaWdodCA9IGhlaWdodCwgCiAgICAgICAgIHdpZHRoID0gd2lkdGgpIAp9CmBgYAoKVGhpcyBzZWN0aW9uIGlzbid0IHdvcnRoIHJlYWRpbmc7IGl0J3MgaGVyZSBzb2xlbHkgdG8gcHJvdmUgdGhhdCB0aGUgZmlndXJlcyB3ZSBwcmVzZW50IGluIG91ciBwdWJsaWNhdGlvbiB3ZXJlIGR5bmFtaWNhbGx5IGdlbmVyYXRlZCBkdXJpbmcgdGhlIGtuaXR0aW5nIG9mIHRoaXMgZG9jdW1lbnQuCgpgYGB7cn0KU2F2ZUZpZ3VyZShteS5wbG90ID0gcDBhLCBuYW1lID0gIlNldXJhdF9DbHVzdGVyc190U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDBiLCBuYW1lID0gIlNldXJhdF9DbHVzdGVyc19TaWxfU2NvcmUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMGMsIG5hbWUgPSAiU2V1cmF0X0NsdXN0ZXJzX0RvdHBsb3QiLCBoZWlnaHQgPSA4LCB3aWR0aCA9IDEyKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMSwgbmFtZSA9ICJTZXVyYXRfQ2x1c3RlcnNfVU1BUCIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAyLCBuYW1lID0gIlNldXJhdF9DbHVzdGVyc19GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMywgbmFtZSA9ICJTaW5nbGVSX0Fubm9zX1NDX1JlZiIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA0LCBuYW1lID0gIlNpbmdsZVJfQW5ub3NfQnVsa19SZWYiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNSwgbmFtZSA9ICJDT05JQ1NtYXRfQW5ub3MiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNiwgbmFtZSA9ICJERUNPREVSX0Jhc2FsIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDcsIG5hbWUgPSAiREVDT0RFUl9DbGFzc2ljYWwiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwOCwgbmFtZSA9ICJERUNPREVSX0V4b2NyaW5lIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDksIG5hbWUgPSAiREVDT0RFUl9FbmRvY3JpbmUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMTAsIG5hbWUgPSAiREVDT0RFUl9JbW11bmUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMTEsIG5hbWUgPSAiREVDT0RFUl9Ob3JtYWxfU3Ryb21hIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDEyLCBuYW1lID0gIkRFQ09ERVJfQWN0X1N0cm9tYSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxMywgbmFtZSA9ICJGaWJyb19BbGxfQ2VsbHNfQ09MMUExIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDE0LCBuYW1lID0gIkZpYnJvX0FsbF9DZWxsc19DT0wzQTEiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMTUsIG5hbWUgPSAiRmlicm9fQWxsX0NlbGxzX0xVTSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxNiwgbmFtZSA9ICJGaWJyb19BbGxfQ2VsbHNfRENOIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDE3LCBuYW1lID0gIkZpYnJvX1NDSVNTT1JTX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxOCwgbmFtZSA9ICJGaWJyb19FbmRvdGhlbGlhbF9QTFZBUCIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxOSwgbmFtZSA9ICJGaWJyb19QZXJpdmFzY3VsYXJfUkdTNSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAyMCwgbmFtZSA9ICJGaWJyb19WQU1faUNBRiIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAyMSwgbmFtZSA9ICJGaWJyb19WQU1fbXlDQUYiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMjIsIG5hbWUgPSAiRmlicm9fVkFNX2FwQ0FGIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDIzYSwgbmFtZSA9ICJGaWJyb19GaW5hbF9MYWJlbHMiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMjNiLCBuYW1lID0gIkZpYnJvX0RvdHBsb3QiLCBoZWlnaHQgPSA4LCB3aWR0aCA9IDEyKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMjQsIG5hbWUgPSAiTktUX0FsbF9DZWxsc19DRDNEIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDI1LCBuYW1lID0gIk5LVF9UdW1vcl9TQ0lTU09SU19GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMjYsIG5hbWUgPSAiTktUX1R1bW9yX0NENFRfSUw3UiIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAyNywgbmFtZSA9ICJOS1RfVHVtb3JfQ0Q0VF9DRDY5IikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDI4LCBuYW1lID0gIk5LVF9UdW1vcl9UcmVnX0lMMlJBIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDI5LCBuYW1lID0gIk5LVF9UdW1vcl9UcmVnX0ZPWFAzIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDMwLCBuYW1lID0gIk5LVF9UdW1vcl9Qcm9saWZfVHJlZ19UT1AyQSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAzMSwgbmFtZSA9ICJOS1RfVHVtb3JfTWFzdF9UUFNBQjEiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMzIsIG5hbWUgPSAiTktUX1R1bW9yX05LX05LRzciKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMzMsIG5hbWUgPSAiTktUX1R1bW9yX05LX1BSRjEiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMzQsIG5hbWUgPSAiTktUX1R1bW9yX0NEOFRfQ0Q4QSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAzNSwgbmFtZSA9ICJOS1RfVHVtb3JfQ0Q4VF9DRDIiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMzYsIG5hbWUgPSAiTktUX1R1bW9yX0ludGVybWVkaWF0ZV9Nb25vX0xZWiIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAzNywgbmFtZSA9ICJOS1RfVHVtb3JfSW50ZXJtZWRpYXRlX01vbm9fSExBRFJBIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDM4LCBuYW1lID0gIk5LVF9UdW1vcl9JbnRlcm1lZGlhdGVfTW9ub19DRDc0IikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDM5LCBuYW1lID0gIk5LVF9UdW1vcl9JbnRlcm1lZGlhdGVfTW9ub19ITEFEUEIxIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDQwYSwgbmFtZSA9ICJOS1RfVHVtb3JfRmluYWxfTGFiZWxzIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDQwYiwgbmFtZSA9ICJOS1RfVHVtb3JfRG90cGxvdCIsIGhlaWdodCA9IDgsIHdpZHRoID0gMTIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA0MSwgbmFtZSA9ICJOS1RfTm9ybV9TQ0lTU09SU19GaXRTTkUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNDIsIG5hbWUgPSAiTktUX05vcm1fQ0Q0VF9JTDdSIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDQzLCBuYW1lID0gIk5LVF9Ob3JtX0NENFRfUzEwMEE0IikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDQ0LCBuYW1lID0gIk5LVF9Ob3JtX0NENFRfQ0NSNyIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA0NSwgbmFtZSA9ICJOS1RfTm9ybV9DRDhUX0NEOEEiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNDYsIG5hbWUgPSAiTktUX05vcm1fVHJlZ19USUdJVCIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA0NywgbmFtZSA9ICJOS1RfTm9ybV9UcmVnX0ZPWFAzIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDQ4LCBuYW1lID0gIk5LVF9Ob3JtX05LX1BSRjEiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNDksIG5hbWUgPSAiTktUX05vcm1fTktfTktHNyIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA1MCwgbmFtZSA9ICJOS1RfTm9ybV9Qcm9saWZfVHJlZ19UT1AyQSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA1MWEsIG5hbWUgPSAiTktUX05vcm1fRmluYWxfTGFiZWxzIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDUxYiwgbmFtZSA9ICJOS1RfTm9ybV9Eb3RwbG90IiwgaGVpZ2h0ID0gOCwgd2lkdGggPSAxMikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDUyLCBuYW1lID0gIkR1Y3RhbF9BbGxfQ2VsbHNfS1JUOCIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA1MywgbmFtZSA9ICJEdWN0YWxfU0NJU1NPUlNfRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDU0LCBuYW1lID0gIkR1Y3RhbF9MaXBpZF9Qcm9jX0FOUEVQIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDU1LCBuYW1lID0gIkR1Y3RhbF9MaXBpZF9Qcm9jX0ZBQlAxIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDU2LCBuYW1lID0gIkR1Y3RhbF9TZWNyZXRvcnlfU09EMyIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA1NywgbmFtZSA9ICJEdWN0YWxfU2VjcmV0b3J5X0NGVFIiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNTgsIG5hbWUgPSAiRHVjdGFsX0NsYXNzaWNhbDFfVEZGMSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA1OSwgbmFtZSA9ICJEdWN0YWxfQ2xhc3NpY2FsMV9URkYyIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDYwLCBuYW1lID0gIkR1Y3RhbF9DbGFzc2ljYWwxX1NhbXBsZUlEIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDYxLCBuYW1lID0gIkR1Y3RhbF9DbGFzc2ljYWwyX0NSSVNQMyIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA2MiwgbmFtZSA9ICJEdWN0YWxfREVDT0RFUl9CYXNhbCIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA2MywgbmFtZSA9ICJEdWN0YWxfQWNpbmFyX0NUUkIyIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDY0YSwgbmFtZSA9ICJEdWN0YWxfRmluYWxfTGFiZWxzIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDY0YiwgbmFtZSA9ICJEdWN0YWxfRG90cGxvdCIsIGhlaWdodCA9IDgsIHdpZHRoID0gMTIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA2NSwgbmFtZSA9ICJQbGFzbWFfQWxsX0NlbGxzX0lHSiIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA2NiwgbmFtZSA9ICJQbGFzbWFjeXRvaWRfRENfQWxsX0NlbGxzX0lSRjciKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNjcsIG5hbWUgPSAiQl9BbGxfQ2VsbHNfTVM0QTEiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNjgsIG5hbWUgPSAiQl9BbGxfQ2VsbHNfQ0Q3OUEiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNjksIG5hbWUgPSAiQl9BbGxfQ2VsbHNfVGlzc3VlX1R5cGUiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNzAsIG5hbWUgPSAiTXllbG9pZF9UdW1vcl9BbGxfQ2VsbHNfRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDcxLCBuYW1lID0gIk15ZWxvaWRfVHVtb3JfQWxsX0NlbGxzX0NEMTQiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNzIsIG5hbWUgPSAiTXllbG9pZF9UdW1vcl9BbGxfQ2VsbHNfQzFRQSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA3MywgbmFtZSA9ICJNeWVsb2lkX1R1bW9yX0FsbF9DZWxsc19TUFAxIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDc0LCBuYW1lID0gIk15ZWxvaWRfVHVtb3JfQWxsX0NlbGxzX0xZWiIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA3NSwgbmFtZSA9ICJNeWVsb2lkX1R1bW9yX0FsbF9DZWxsc19TMTAwQTgiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwNzYsIG5hbWUgPSAiTXllbG9pZF9UdW1vcl9BbGxfQ2VsbHNfRkNFUjFBIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDc3LCBuYW1lID0gIk15ZWxvaWRfVHVtb3JfU0NJU1NPUlNfRml0U05FIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDc4LCBuYW1lID0gIkRDX1R1bW9yX1NDSVNTT1JTX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA3OSwgbmFtZSA9ICJNeWVsb2lkX1R1bW9yX05ldXRyb3BoaWxfUzEwMEE4IikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDgwLCBuYW1lID0gIk15ZWxvaWRfVHVtb3JfTmV1dHJvcGhpbF9TMTAwQTkiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwODEsIG5hbWUgPSAiTXllbG9pZF9UdW1vcl9DbGFzc2ljX01vbm9fQ0QxNCIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA4MiwgbmFtZSA9ICJNeWVsb2lkX1R1bW9yX0NEMTZfTW9ub19GQ0dSM0EiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwODMsIG5hbWUgPSAiTXllbG9pZF9UdW1vcl9DRDE2X01vbm9fTVM0QTciKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwODQsIG5hbWUgPSAiTXllbG9pZF9UdW1vcl9DRDE2X01vbm9fUzEwMEExMCIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA4NSwgbmFtZSA9ICJNeWVsb2lkX1R1bW9yX1Jlc2lkZW50X01hY3JvX0MxUUEiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwODYsIG5hbWUgPSAiTXllbG9pZF9UdW1vcl9BbHRfQWN0aXZhdGVkX01hY3JvX0FQT0UiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwODcsIG5hbWUgPSAiTXllbG9pZF9UdW1vcl9BbHRfQWN0aXZhdGVkX01hY3JvX1NQUDEiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwODgsIG5hbWUgPSAiRENfVHVtb3JfY0RDMV9DTEVDOUEiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwODksIG5hbWUgPSAiRENfVHVtb3JfTGFuZ2VyaGFuc19EQ19DRDFBIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDkwLCBuYW1lID0gIkRDX1R1bW9yX0xhbmdlcmhhbnNfRENfQ0QyMDciKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwOTEsIG5hbWUgPSAiRENfVHVtb3JfQWN0aXZhdGVkX0RDX0xBTVAzIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDkyLCBuYW1lID0gIkRDX1R1bW9yX2NEQzJfQ0xFQzEwQSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA5MywgbmFtZSA9ICJEQ19UdW1vcl9jREMyX0tMRjQiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwOTQsIG5hbWUgPSAiRENfVHVtb3JfU2FtcGxlX0lEIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDk1YSwgbmFtZSA9ICJNeWVsb2lkX1R1bW9yX0ZpbmFsX0xhYmVscyIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA5NWIsIG5hbWUgPSAiTXllbG9pZF9UdW1vcl9Eb3RwbG90IiwgaGVpZ2h0ID0gOCwgd2lkdGggPSAxMikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDk2YSwgbmFtZSA9ICJEQ19UdW1vcl9GaW5hbF9MYWJlbHMiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwOTZiLCBuYW1lID0gIkRDX1R1bW9yX0RvdHBsb3QiLCBoZWlnaHQgPSA4LCB3aWR0aCA9IDEyKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwOTcsIG5hbWUgPSAiTXllbG9pZF9Ob3JtX1NDSVNTT1JTX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA5OCwgbmFtZSA9ICJEQ19Ob3JtX1NDSVNTT1JTX0ZpdFNORSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHA5OSwgbmFtZSA9ICJNeWVsb2lkX05vcm1fTmV1dHJvcGhpbF9TMTAwQTgiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMTAwLCBuYW1lID0gIk15ZWxvaWRfTm9ybV9OZXV0cm9waGlsX1MxMDBBOSIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxMDEsIG5hbWUgPSAiTXllbG9pZF9Ob3JtX0NsYXNzaWNfTW9ub19MWVoiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMTAyLCBuYW1lID0gIk15ZWxvaWRfTm9ybV9DbGFzc2ljX01vbm9fQ0QxNCIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxMDMsIG5hbWUgPSAiTXllbG9pZF9Ob3JtX1NhbXBsZV9JRCIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxMDQsIG5hbWUgPSAiTXllbG9pZF9Ob3JtX1Jlc2lkZW50X01hY3JvX0MxUUEiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMTA1LCBuYW1lID0gIk15ZWxvaWRfTm9ybV9BbHRfQWN0aXZhdGVkX01hY3JvX0FQT0UiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMTA2LCBuYW1lID0gIk15ZWxvaWRfTm9ybV9DRDhUX0NEM0QiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMTA3LCBuYW1lID0gIk15ZWxvaWRfTm9ybV9DRDhUX0NEOEEiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMTA4LCBuYW1lID0gIk15ZWxvaWRfTm9ybV9DRDhUX05LRzciKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMTA5LCBuYW1lID0gIkRDX05vcm1fY0RDMV9DTEVDOUEiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMTEwLCBuYW1lID0gIkRDX05vcm1fY0RDMl9DTEVDMTBBIikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDExMWEsIG5hbWUgPSAiTXllbG9pZF9Ob3JtX0ZpbmFsX0xhYmVscyIpClNhdmVGaWd1cmUobXkucGxvdCA9IHAxMTFiLCBuYW1lID0gIk15ZWxvaWRfTm9ybV9Eb3RwbG90IiwgaGVpZ2h0ID0gOCwgd2lkdGggPSAxMikKU2F2ZUZpZ3VyZShteS5wbG90ID0gcDExMmEsIG5hbWUgPSAiRENfTm9ybV9GaW5hbF9MYWJlbHMiKQpTYXZlRmlndXJlKG15LnBsb3QgPSBwMTEyYiwgbmFtZSA9ICJEQ19Ob3JtX0RvdHBsb3QiLCBoZWlnaHQgPSA4LCB3aWR0aCA9IDEyKQpgYGAKCkFuZCBvZiBjb3Vyc2U6CgpgYGB7cn0Kc2Vzc2lvbkluZm8oKQpgYGAK